summaryrefslogtreecommitdiffstats
path: root/nsprpub/pr/tests
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--nsprpub/pr/tests/Makefile.in446
-rw-r--r--nsprpub/pr/tests/README.TXT404
-rw-r--r--nsprpub/pr/tests/abstract.c157
-rw-r--r--nsprpub/pr/tests/accept.c508
-rw-r--r--nsprpub/pr/tests/acceptread.c270
-rw-r--r--nsprpub/pr/tests/acceptreademu.c300
-rw-r--r--nsprpub/pr/tests/addrstr.c82
-rw-r--r--nsprpub/pr/tests/affinity.c84
-rw-r--r--nsprpub/pr/tests/alarm.c552
-rw-r--r--nsprpub/pr/tests/anonfm.c319
-rw-r--r--nsprpub/pr/tests/append.c146
-rw-r--r--nsprpub/pr/tests/atomic.c183
-rw-r--r--nsprpub/pr/tests/attach.c299
-rw-r--r--nsprpub/pr/tests/bigfile.c358
-rw-r--r--nsprpub/pr/tests/bigfile2.c100
-rw-r--r--nsprpub/pr/tests/bigfile3.c99
-rw-r--r--nsprpub/pr/tests/bug1test.c230
-rw-r--r--nsprpub/pr/tests/cleanup.c103
-rw-r--r--nsprpub/pr/tests/cltsrv.c1271
-rw-r--r--nsprpub/pr/tests/concur.c166
-rw-r--r--nsprpub/pr/tests/cvar.c309
-rw-r--r--nsprpub/pr/tests/cvar2.c976
-rw-r--r--nsprpub/pr/tests/dbmalloc.c339
-rw-r--r--nsprpub/pr/tests/dbmalloc1.c114
-rw-r--r--nsprpub/pr/tests/dceemu.c109
-rw-r--r--nsprpub/pr/tests/depend.c132
-rw-r--r--nsprpub/pr/tests/dll/Makefile.in77
-rw-r--r--nsprpub/pr/tests/dll/my.def26
-rw-r--r--nsprpub/pr/tests/dll/mygetval.c26
-rw-r--r--nsprpub/pr/tests/dll/mysetval.c13
-rw-r--r--nsprpub/pr/tests/dlltest.c216
-rw-r--r--nsprpub/pr/tests/dtoa.c213
-rw-r--r--nsprpub/pr/tests/env.c370
-rw-r--r--nsprpub/pr/tests/errcodes.c136
-rw-r--r--nsprpub/pr/tests/errset.c155
-rw-r--r--nsprpub/pr/tests/exit.c110
-rw-r--r--nsprpub/pr/tests/fdcach.c125
-rw-r--r--nsprpub/pr/tests/fileio.c214
-rw-r--r--nsprpub/pr/tests/foreign.c321
-rw-r--r--nsprpub/pr/tests/forktest.c254
-rw-r--r--nsprpub/pr/tests/formattm.c50
-rw-r--r--nsprpub/pr/tests/freeif.c47
-rw-r--r--nsprpub/pr/tests/fsync.c130
-rw-r--r--nsprpub/pr/tests/getai.c32
-rw-r--r--nsprpub/pr/tests/gethost.c267
-rw-r--r--nsprpub/pr/tests/getproto.c90
-rw-r--r--nsprpub/pr/tests/i2l.c103
-rw-r--r--nsprpub/pr/tests/initclk.c77
-rw-r--r--nsprpub/pr/tests/inrval.c217
-rw-r--r--nsprpub/pr/tests/instrumt.c478
-rw-r--r--nsprpub/pr/tests/intrio.c132
-rw-r--r--nsprpub/pr/tests/intrupt.c379
-rw-r--r--nsprpub/pr/tests/io_timeout.c269
-rw-r--r--nsprpub/pr/tests/io_timeoutk.c229
-rw-r--r--nsprpub/pr/tests/io_timeoutu.c230
-rw-r--r--nsprpub/pr/tests/ioconthr.c114
-rw-r--r--nsprpub/pr/tests/ipv6.c228
-rw-r--r--nsprpub/pr/tests/join.c264
-rw-r--r--nsprpub/pr/tests/joinkk.c174
-rw-r--r--nsprpub/pr/tests/joinku.c181
-rw-r--r--nsprpub/pr/tests/joinuk.c177
-rw-r--r--nsprpub/pr/tests/joinuu.c179
-rw-r--r--nsprpub/pr/tests/layer.c471
-rw-r--r--nsprpub/pr/tests/lazyinit.c108
-rw-r--r--nsprpub/pr/tests/libfilename.c101
-rw-r--r--nsprpub/pr/tests/lltest.c969
-rw-r--r--nsprpub/pr/tests/lock.c548
-rw-r--r--nsprpub/pr/tests/lockfile.c255
-rw-r--r--nsprpub/pr/tests/logfile.c38
-rw-r--r--nsprpub/pr/tests/logger.c127
-rw-r--r--nsprpub/pr/tests/makedir.c67
-rw-r--r--nsprpub/pr/tests/many_cv.c124
-rw-r--r--nsprpub/pr/tests/mbcs.c159
-rw-r--r--nsprpub/pr/tests/monref.c74
-rw-r--r--nsprpub/pr/tests/multiacc.c220
-rw-r--r--nsprpub/pr/tests/multiwait.c785
-rw-r--r--nsprpub/pr/tests/nameshm1.c586
-rw-r--r--nsprpub/pr/tests/nbconn.c531
-rw-r--r--nsprpub/pr/tests/nblayer.c778
-rw-r--r--nsprpub/pr/tests/nonblock.c223
-rw-r--r--nsprpub/pr/tests/ntioto.c319
-rw-r--r--nsprpub/pr/tests/ntoh.c93
-rw-r--r--nsprpub/pr/tests/obsints.c51
-rw-r--r--nsprpub/pr/tests/op_2long.c75
-rw-r--r--nsprpub/pr/tests/op_excl.c138
-rw-r--r--nsprpub/pr/tests/op_filnf.c51
-rw-r--r--nsprpub/pr/tests/op_filok.c48
-rw-r--r--nsprpub/pr/tests/op_noacc.c51
-rw-r--r--nsprpub/pr/tests/op_nofil.c56
-rw-r--r--nsprpub/pr/tests/openfile.c113
-rw-r--r--nsprpub/pr/tests/parent.c131
-rw-r--r--nsprpub/pr/tests/parsetm.c90
-rw-r--r--nsprpub/pr/tests/peek.c362
-rw-r--r--nsprpub/pr/tests/perf.c447
-rw-r--r--nsprpub/pr/tests/pipeping.c158
-rw-r--r--nsprpub/pr/tests/pipeping2.c160
-rw-r--r--nsprpub/pr/tests/pipepong.c60
-rw-r--r--nsprpub/pr/tests/pipepong2.c98
-rw-r--r--nsprpub/pr/tests/pipeself.c228
-rw-r--r--nsprpub/pr/tests/poll_er.c210
-rw-r--r--nsprpub/pr/tests/poll_nm.c355
-rw-r--r--nsprpub/pr/tests/poll_to.c209
-rw-r--r--nsprpub/pr/tests/pollable.c261
-rw-r--r--nsprpub/pr/tests/prfdbl.c29
-rw-r--r--nsprpub/pr/tests/prftest.c66
-rw-r--r--nsprpub/pr/tests/prftest1.c129
-rw-r--r--nsprpub/pr/tests/prftest2.c103
-rw-r--r--nsprpub/pr/tests/prfz.c85
-rw-r--r--nsprpub/pr/tests/primblok.c116
-rw-r--r--nsprpub/pr/tests/priotest.c202
-rw-r--r--nsprpub/pr/tests/provider.c1412
-rw-r--r--nsprpub/pr/tests/prpoll.c351
-rw-r--r--nsprpub/pr/tests/prpollml.c136
-rw-r--r--nsprpub/pr/tests/prselect.c368
-rw-r--r--nsprpub/pr/tests/prttools.h11
-rw-r--r--nsprpub/pr/tests/pushtop.c73
-rw-r--r--nsprpub/pr/tests/randseed.c137
-rw-r--r--nsprpub/pr/tests/ranfile.c433
-rw-r--r--nsprpub/pr/tests/reinit.c35
-rw-r--r--nsprpub/pr/tests/rmdir.c99
-rwxr-xr-xnsprpub/pr/tests/runtests.pl371
-rwxr-xr-xnsprpub/pr/tests/runtests.sh277
-rw-r--r--nsprpub/pr/tests/runy2ktests.ksh237
-rw-r--r--nsprpub/pr/tests/rwlockrank.c122
-rw-r--r--nsprpub/pr/tests/rwlocktest.c213
-rw-r--r--nsprpub/pr/tests/sel_spd.c534
-rw-r--r--nsprpub/pr/tests/selct_er.c200
-rw-r--r--nsprpub/pr/tests/selct_nm.c294
-rw-r--r--nsprpub/pr/tests/selct_to.c182
-rw-r--r--nsprpub/pr/tests/select2.c385
-rw-r--r--nsprpub/pr/tests/selintr.c49
-rw-r--r--nsprpub/pr/tests/sem.c222
-rw-r--r--nsprpub/pr/tests/sema.c165
-rw-r--r--nsprpub/pr/tests/semaerr.c124
-rw-r--r--nsprpub/pr/tests/semaerr1.c118
-rw-r--r--nsprpub/pr/tests/semaping.c187
-rw-r--r--nsprpub/pr/tests/semapong.c130
-rw-r--r--nsprpub/pr/tests/sendzlf.c214
-rw-r--r--nsprpub/pr/tests/server_test.c692
-rw-r--r--nsprpub/pr/tests/servr_kk.c659
-rw-r--r--nsprpub/pr/tests/servr_ku.c639
-rw-r--r--nsprpub/pr/tests/servr_uk.c640
-rw-r--r--nsprpub/pr/tests/servr_uu.c640
-rw-r--r--nsprpub/pr/tests/short_thread.c60
-rw-r--r--nsprpub/pr/tests/sigpipe.c94
-rw-r--r--nsprpub/pr/tests/sleep.c105
-rw-r--r--nsprpub/pr/tests/socket.c2286
-rw-r--r--nsprpub/pr/tests/sockopt.c178
-rw-r--r--nsprpub/pr/tests/sockping.c132
-rw-r--r--nsprpub/pr/tests/sockpong.c83
-rw-r--r--nsprpub/pr/tests/sprintf.c459
-rw-r--r--nsprpub/pr/tests/stack.c282
-rw-r--r--nsprpub/pr/tests/stat.c87
-rw-r--r--nsprpub/pr/tests/stdio.c51
-rw-r--r--nsprpub/pr/tests/str2addr.c50
-rw-r--r--nsprpub/pr/tests/strod.c76
-rw-r--r--nsprpub/pr/tests/suspend.c177
-rw-r--r--nsprpub/pr/tests/switch.c252
-rw-r--r--nsprpub/pr/tests/system.c56
-rw-r--r--nsprpub/pr/tests/testbit.c111
-rw-r--r--nsprpub/pr/tests/testfile.c963
-rw-r--r--nsprpub/pr/tests/threads.c211
-rw-r--r--nsprpub/pr/tests/thrpool_client.c349
-rw-r--r--nsprpub/pr/tests/thrpool_server.c579
-rw-r--r--nsprpub/pr/tests/thruput.c414
-rw-r--r--nsprpub/pr/tests/time.c177
-rw-r--r--nsprpub/pr/tests/timemac.c112
-rw-r--r--nsprpub/pr/tests/timetest.c823
-rw-r--r--nsprpub/pr/tests/tmoacc.c339
-rw-r--r--nsprpub/pr/tests/tmocon.c435
-rw-r--r--nsprpub/pr/tests/tpd.c308
-rw-r--r--nsprpub/pr/tests/udpsrv.c546
-rw-r--r--nsprpub/pr/tests/ut_ttools.h11
-rw-r--r--nsprpub/pr/tests/vercheck.c92
-rw-r--r--nsprpub/pr/tests/version.c94
-rw-r--r--nsprpub/pr/tests/writev.c225
-rw-r--r--nsprpub/pr/tests/xnotify.c429
-rw-r--r--nsprpub/pr/tests/y2k.c799
-rw-r--r--nsprpub/pr/tests/y2ktmo.c554
-rw-r--r--nsprpub/pr/tests/yield.c57
-rw-r--r--nsprpub/pr/tests/zerolen.c250
181 files changed, 47672 insertions, 0 deletions
diff --git a/nsprpub/pr/tests/Makefile.in b/nsprpub/pr/tests/Makefile.in
new file mode 100644
index 0000000000..a58a846927
--- /dev/null
+++ b/nsprpub/pr/tests/Makefile.in
@@ -0,0 +1,446 @@
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+#! gmake
+
+MOD_DEPTH = ../..
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+include $(MOD_DEPTH)/config/autoconf.mk
+
+include $(topsrcdir)/config/config.mk
+
+DIRS = dll
+
+CSRCS = \
+ abstract.c \
+ accept.c \
+ acceptread.c \
+ acceptreademu.c \
+ addrstr.c \
+ affinity.c \
+ alarm.c \
+ anonfm.c \
+ append.c \
+ atomic.c \
+ attach.c \
+ bigfile.c \
+ bigfile2.c \
+ bigfile3.c \
+ cleanup.c \
+ cltsrv.c \
+ concur.c \
+ cvar.c \
+ cvar2.c \
+ dceemu.c \
+ dlltest.c \
+ dtoa.c \
+ env.c \
+ errcodes.c \
+ errset.c \
+ exit.c \
+ fdcach.c \
+ fileio.c \
+ foreign.c \
+ forktest.c \
+ formattm.c \
+ fsync.c \
+ getai.c \
+ gethost.c \
+ getproto.c \
+ i2l.c \
+ initclk.c \
+ inrval.c \
+ instrumt.c \
+ intrio.c \
+ intrupt.c \
+ io_timeout.c \
+ ioconthr.c \
+ ipv6.c \
+ join.c \
+ joinkk.c \
+ joinku.c \
+ joinuk.c \
+ joinuu.c \
+ layer.c \
+ lazyinit.c \
+ libfilename.c \
+ lltest.c \
+ lock.c \
+ lockfile.c \
+ logfile.c \
+ logger.c \
+ makedir.c \
+ mbcs.c \
+ multiacc.c \
+ multiwait.c \
+ many_cv.c \
+ monref.c \
+ nameshm1.c \
+ nbconn.c \
+ nblayer.c \
+ nonblock.c \
+ ntioto.c \
+ ntoh.c \
+ obsints.c \
+ op_2long.c \
+ op_excl.c \
+ op_filnf.c \
+ op_filok.c \
+ op_noacc.c \
+ op_nofil.c \
+ openfile.c \
+ parent.c \
+ parsetm.c \
+ peek.c \
+ perf.c \
+ pipeping.c \
+ pipeping2.c \
+ pipepong.c \
+ pipepong2.c \
+ pipeself.c \
+ poll_er.c \
+ poll_nm.c \
+ poll_to.c \
+ pollable.c \
+ prfdbl.c \
+ prftest.c \
+ prftest1.c \
+ prftest2.c \
+ prfz.c \
+ primblok.c \
+ priotest.c \
+ provider.c \
+ prpoll.c \
+ prpollml.c \
+ pushtop.c \
+ ranfile.c \
+ randseed.c \
+ reinit.c \
+ rmdir.c \
+ rwlockrank.c \
+ rwlocktest.c \
+ sel_spd.c \
+ selct_er.c \
+ selct_nm.c \
+ selct_to.c \
+ select2.c \
+ selintr.c \
+ sem.c \
+ sema.c \
+ semaerr.c \
+ semaerr1.c \
+ semaping.c \
+ semapong.c \
+ sendzlf.c \
+ server_test.c \
+ servr_kk.c \
+ servr_ku.c \
+ servr_uk.c \
+ servr_uu.c \
+ short_thread.c \
+ sigpipe.c \
+ socket.c \
+ sockopt.c \
+ sockping.c \
+ sockpong.c \
+ sprintf.c \
+ stack.c \
+ stdio.c \
+ str2addr.c \
+ strod.c \
+ suspend.c \
+ switch.c \
+ system.c \
+ testbit.c \
+ testfile.c \
+ thrpool_server.c \
+ thrpool_client.c \
+ threads.c \
+ thruput.c \
+ timemac.c \
+ timetest.c \
+ tmoacc.c \
+ tmocon.c \
+ tpd.c \
+ vercheck.c \
+ version.c \
+ udpsrv.c \
+ writev.c \
+ xnotify.c \
+ y2k.c \
+ y2ktmo.c \
+ zerolen.c \
+ $(NULL)
+
+ifeq ($(OS_ARCH),WINCE)
+CFLAGS += -FImozce_shunt.h -Zi -UDEBUG -DNDEBUG
+LDOPTS += -link $(DIST)/lib/mozce_shunt.lib ws2.lib -DEBUG -DEBUGTYPE:CV -INCREMENTAL:NO -PDB:$(@:.exe=.pdb)
+endif
+
+ifeq ($(OS_TARGET),OS2)
+CSRCS += \
+ sleep.c \
+ stat.c \
+ yield.c \
+ $(NULL)
+endif
+
+ifeq (,$(filter-out WINCE WINNT OS2,$(OS_ARCH)))
+PROG_SUFFIX = .exe
+DLL_SUFFIX = .dll
+else
+PROG_SUFFIX =
+DLL_SUFFIX =
+endif
+
+PROGS = $(addprefix $(OBJDIR)/, $(CSRCS:.c=$(PROG_SUFFIX)))
+
+TARGETS = $(PROGS)
+
+INCLUDES = -I$(dist_includedir) -I$(topsrcdir)/pr/include -I$(topsrcdir)/pr/include/private
+
+ifeq ($(OS_ARCH), WINNT)
+ifdef NS_USE_GCC
+ EXTRA_LIBS += -lws2_32
+else
+ EXTRA_LIBS += ws2_32.lib
+ LDOPTS = -NOLOGO -DEBUG -DEBUGTYPE:CV -INCREMENTAL:NO
+ CFLAGS += -Fd$(@:.$(OBJ_SUFFIX)=.pdb)
+ ifdef PROFILE
+ LDOPTS += -PROFILE -MAP
+ endif # profile
+endif # NS_USE_GCC
+endif
+
+ifeq ($(OS_ARCH),OS2)
+EXTRA_LIBS = $(OS_LIBS)
+LDOPTS = -Zomf -Zlinker /PM:VIO -Zlinker /ST:0x64000
+endif
+
+ifneq ($(OS_ARCH), WINNT)
+# Use an absolute pathname as the runtime library path (for the -R
+# or -rpath linker option or the LD_RUN_PATH environment variable).
+ifeq (,$(patsubst /%,,$(DIST)))
+# $(DIST) is already an absolute pathname.
+ABSOLUTE_LIB_DIR = $(dist_libdir)
+else
+# $(DIST) is a relative pathname: prepend the current directory.
+PWD = $(shell pwd)
+ABSOLUTE_LIB_DIR = $(PWD)/$(dist_libdir)
+endif
+endif
+
+ifeq ($(OS_ARCH), HP-UX)
+ LDOPTS += -z -Wl,+s,+b,$(ABSOLUTE_LIB_DIR)
+ ifeq ($(USE_64),1)
+ LDOPTS += +DD64
+ endif
+ ifeq ($(USE_PTHREADS),1)
+ EXTRA_LIBS = $(LIBPTHREAD)
+ endif
+endif
+
+# AIX
+ifeq ($(OS_ARCH),AIX)
+ LDOPTS += -blibpath:$(ABSOLUTE_LIB_DIR):/usr/lib:/lib
+ ifneq ($(OS_ARCH)$(OS_RELEASE),AIX4.1)
+ LDOPTS += -brtl
+ EXTRA_LIBS = -ldl
+ endif
+endif
+
+# Solaris
+ifeq ($(OS_ARCH), SunOS)
+ ifdef NS_USE_GCC
+ LDOPTS += -Xlinker -R -Xlinker $(ABSOLUTE_LIB_DIR)
+ else
+ ifeq ($(USE_CPLUS), 1)
+ CC = CC
+ endif
+ LDOPTS += -R $(ABSOLUTE_LIB_DIR)
+ endif
+
+ ifdef USE_PTHREADS
+ EXTRA_LIBS = -lpthread
+ endif
+endif # SunOS
+
+ifeq (,$(filter-out Linux GNU GNU_%,$(OS_ARCH)))
+ LDOPTS += -Xlinker -rpath $(ABSOLUTE_LIB_DIR)
+ ifeq ($(USE_PTHREADS),1)
+ EXTRA_LIBS = -lpthread
+ endif
+endif
+
+ifeq ($(OS_ARCH), SCOOS)
+# SCO Unix needs to link against -lsocket again even though we
+# already linked with these system libraries when we built libnspr.so.
+EXTRA_LIBS = -lsocket
+# This hardcodes in the executable programs the directory to find
+# libnspr.so etc. at program startup. Equivalent to the -R or -rpath
+# option for ld on other platforms.
+export LD_RUN_PATH = $(ABSOLUTE_LIB_DIR)
+endif
+
+ifeq ($(OS_ARCH),OpenUNIX)
+export LD_RUN_PATH = $(ABSOLUTE_LIB_DIR)
+ifeq ($(USE_PTHREADS),1)
+LDOPTS += -pthread
+endif
+endif
+
+ifeq ($(OS_ARCH), UNIXWARE)
+export LD_RUN_PATH = $(ABSOLUTE_LIB_DIR)
+endif
+
+ifeq ($(OS_ARCH),FreeBSD)
+ifeq ($(USE_PTHREADS),1)
+LDOPTS += -pthread
+endif
+LDOPTS += -Xlinker -R $(ABSOLUTE_LIB_DIR)
+endif
+
+ifeq ($(OS_ARCH),OpenBSD)
+ifeq ($(USE_PTHREADS),1)
+LDOPTS += -pthread
+endif
+endif
+
+ifeq ($(OS_ARCH),BSD_OS)
+ifneq ($(OS_RELEASE),1.1)
+EXTRA_LIBS = -ldl
+endif
+endif
+
+ifeq ($(OS_ARCH),RISCOS)
+EXTRA_LIBS = -ldl
+endif
+
+ifeq ($(USE_PTHREADS),1)
+LIBPTHREAD = -lpthread
+ifeq ($(OS_ARCH),AIX)
+LIBPTHREAD = -lpthreads
+endif
+ifeq (,$(filter-out FreeBSD OpenBSD BSD_OS QNX Darwin OpenUNIX,$(OS_ARCH)))
+LIBPTHREAD =
+endif
+endif
+
+ifeq ($(OS_TARGET),Android)
+LIBPTHREAD =
+XCFLAGS = $(OS_CFLAGS)
+endif
+
+#####################################################
+#
+# The rules
+#
+#####################################################
+
+include $(topsrcdir)/config/rules.mk
+
+AIX_PRE_4_2 = 0
+ifeq ($(OS_ARCH),AIX)
+ifeq ($(OS_RELEASE),4.1)
+ifneq ($(USE_PTHREADS), 1)
+#AIX_PRE_4_2 = 1
+endif
+endif
+endif
+
+ifeq ($(AIX_PRE_4_2),1)
+
+# AIX releases prior to 4.2 need a special two-step linking hack
+# in order to both override the system select() and be able to
+# get at the original system select().
+#
+# We use a pattern rule in ns/nspr20/config/rules.mk to generate
+# the .$(OBJ_SUFFIX) file from the .c source file, then do the
+# two-step linking hack below.
+
+$(OBJDIR)/%: $(OBJDIR)/%.$(OBJ_SUFFIX)
+ @$(MAKE_OBJDIR)
+ rm -f $@ $(AIX_TMP)
+ $(CC) $(AIX_LINK_OPTS) -o $(AIX_TMP) $< $(dist_libdir)/libnspr$(MOD_MAJOR_VERSION).a
+ $(CC) -o $@ $(AIX_TMP) $(AIX_WRAP)
+ rm -f $(AIX_TMP)
+
+else
+
+# All platforms that are not AIX pre-4.2.
+
+$(OBJDIR)/%$(PROG_SUFFIX): $(OBJDIR)/%.$(OBJ_SUFFIX)
+ @$(MAKE_OBJDIR)
+ifeq ($(NS_USE_GCC)_$(OS_ARCH),_WINNT)
+ link $(LDOPTS) $(EXTRA_LDOPTS) $< $(LIBPLC) $(LIBNSPR) $(EXTRA_LIBS) -out:$@
+ifdef MT
+ @if test -f $@.manifest; then \
+ $(MT) -NOLOGO -MANIFEST $@.manifest -OUTPUTRESOURCE:$@\;1; \
+ rm -f $@.manifest; \
+ fi
+endif
+else
+ $(PURE) $(CC) $(XCFLAGS) $< $(LDOPTS) $(LIBPLC) $(LIBNSPR) $(EXTRA_LIBS) -o $@
+endif # WINNT
+endif # AIX_PRE_4_2
+
+export:: $(TARGETS)
+clean::
+ rm -f $(TARGETS)
+
+# The following tests call BSD socket functions, so they need to link
+# with -lsocket on some platforms.
+ifeq ($(OS_ARCH),SunOS)
+ifeq ($(USE_IPV6),1)
+$(OBJDIR)/gethost: $(OBJDIR)/gethost.o
+ $(PURE) $(CC) $(XCFLAGS) $< $(LDOPTS) $(LIBPLC) $(LIBNSPR) -lsocket $(EXTRA_LIBS) -o $@
+endif
+$(OBJDIR)/prpoll: $(OBJDIR)/prpoll.o
+ $(PURE) $(CC) $(XCFLAGS) $< $(LDOPTS) $(LIBPLC) $(LIBNSPR) -lsocket $(EXTRA_LIBS) -o $@
+endif
+
+ifeq ($(USE_PTHREADS), 1)
+$(OBJDIR)/attach: $(OBJDIR)/attach.o
+ $(PURE) $(CC) $(XCFLAGS) $< $(LDOPTS) $(LIBPLC) $(LIBNSPR) $(LIBPTHREAD) $(EXTRA_LIBS) -o $@
+$(OBJDIR)/foreign: $(OBJDIR)/foreign.o
+ $(PURE) $(CC) $(XCFLAGS) $< $(LDOPTS) $(LIBPLC) $(LIBNSPR) $(LIBPTHREAD) $(EXTRA_LIBS) -o $@
+$(OBJDIR)/provider: $(OBJDIR)/provider.o
+ $(PURE) $(CC) $(XCFLAGS) $< $(LDOPTS) $(LIBPLC) $(LIBNSPR) $(LIBPTHREAD) $(EXTRA_LIBS) -o $@
+$(OBJDIR)/socket: $(OBJDIR)/socket.o
+ $(PURE) $(CC) $(XCFLAGS) $< $(LDOPTS) $(LIBPLC) $(LIBNSPR) $(LIBPTHREAD) $(EXTRA_LIBS) -o $@
+$(OBJDIR)/testfile: $(OBJDIR)/testfile.o
+ $(PURE) $(CC) $(XCFLAGS) $< $(LDOPTS) $(LIBPLC) $(LIBNSPR) $(LIBPTHREAD) $(EXTRA_LIBS) -o $@
+endif
+
+#
+# Run the test programs with no arguments
+#
+# Test output goes to the file pointed to by the environment variable
+# NSPR_TEST_LOGFILE, if set, else to /dev/null
+#
+ECHO = echo
+PROGRAMS = $(notdir $(PROGS))
+ifdef NSPR_TEST_LOGFILE
+LOGFILE = $(NSPR_TEST_LOGFILE)
+else
+ifeq (,$(filter-out WINNT OS2,$(OS_ARCH)))
+LOGFILE = nul
+else
+LOGFILE = /dev/null
+endif
+endif
+
+ifeq ($(OS_TARGET),Linux)
+ECHO = /bin/echo
+endif
+
+ALWAYS:
+
+runtests:: $(PROGS) ALWAYS
+ $(topsrcdir)/pr/tests/runtests.sh $(DIST)
diff --git a/nsprpub/pr/tests/README.TXT b/nsprpub/pr/tests/README.TXT
new file mode 100644
index 0000000000..ebae6cdceb
--- /dev/null
+++ b/nsprpub/pr/tests/README.TXT
@@ -0,0 +1,404 @@
+File: pr/tests/readme
+
+This document describes the test cases in the NSPR directory
+pr/tests.
+
+=====================================================================
+There is a sub-directory here:
+
+dll
+ sources for the .dll(.so) used by test dlltest.c
+
+=====================================================================
+The individual files are described here.
+
+The script 'runtests.ksh' enumerates and runs test cases that are
+expected to run on all platforms.
+
+
+accept.c
+ Tests PR_Accept() and related socket functions.
+
+acceptread.c
+ Tests PR_AcceptRead()
+
+alarm.c
+ Tests alarm functions declared in obsolete/pralarm.h.
+ The alarm functions are obsolete, so is this test.
+
+atomic.c
+ Tests Atomic operations defined in pratom.h
+
+attach.c
+ Test PR_AttachThread()
+ Note: This is an NSPR private function.
+
+bigfile.c
+ Test 64bit file offset functions declared in prio.h
+
+bug1test.c
+ Demonstrates a bug on NT.
+
+cleanup.c
+ Tests PR_Cleanup() declared in prinit.h
+
+cltsrv.c
+ Tests many socket functions.
+
+concur.c
+ Tests threading functions and concurrent operations.
+
+cvar.c
+ Tests condition variables.
+
+cvar2.c
+ Tests condition variables. A rather abusive test.
+
+dbmalloc.c
+ Obsolete. Originally for testing debug builds of NSPR's malloc.
+
+dbmalloc1.c
+ Obsolete. Originally for testing debug builds of NSPR's malloc.
+
+dceemu.c
+ Tests special functions for DCE emulation.
+
+depend.c
+ Obsoltet. Tests early spec for library dependency.
+
+dlltest.c
+ Tests dynamic library functions. Used with dll/my.c
+
+dtoa.c
+ Tests conversions of double to string.
+
+exit.c
+ Tests PR_ProcessExit() declared in prinit.h
+
+fileio.c
+ Tests NSPR semaphores a bit of file i/o and threading
+ functions.
+
+foreign.c
+ Test auto-attach of a thread created by something other than
+ NSPR.
+
+forktest.c
+ Limited use. Tests unix fork() and related functions.
+
+fsync.c
+ Tests use of PR_Sync() declared in prio.h
+
+getproto.c
+ Tests socket functions PR_GetProtoByName(), etc.
+
+i2l.c
+ Tests LongLong functions for converting 32bit integer to 64bit
+ integer.
+
+initclk.c
+ Tests timing on minimal use of condition variable
+
+inrval.c
+ Tests interval timing functions.
+
+instrumt.c
+ Tests instrumentation functions. prcountr.h prtrace.h
+
+intrupt.c
+ Tests PR_Interrupt()
+
+ioconthr.c
+ Tests i/o continuation mechanism in pthreads.
+
+io_timeout.c
+ Test socket i/o timeouts.
+
+io_timeoutk.c
+ Obsolete. Subsumed in io_timeout.c
+
+io_timeoutu.c
+ Obsolete. Subsumed in io_timeout.c
+
+ipv6.c
+ Tests IPv6. IPv6 is not used by NSPR clients.
+
+join.c
+ Tests PR_JoinThread()
+
+joinkk.c
+ Tests PR_JoinThread()
+
+joinku.c
+ Tests PR_JoinThread()
+
+joinuk.c
+ Tests PR_JoinThread()
+
+joinuu.c
+ Tests PR_JoinThread()
+
+layer.c
+ Tests layered I/O.
+
+lazyinit.c
+ Tests implicit initialization.
+
+lltest.c
+ Tests LongLong (64bit integer) arithmentic and conversions.
+
+lock.c
+ Tests PR_Lock() in heavily threaded environment.
+
+lockfile.c
+ Test PR_Lockfile().
+
+logger.c
+ Tests PR_LOG()
+
+makefile
+ The makefile that builds all the tests
+
+many_cv.c
+ Tests aquiring a large number of condition variables.
+
+multiwait.c
+ ???
+
+nbconn.c
+ Test non-blocking connect.
+
+nblayer.c
+ Tests NSPR's layered I/O capability.
+
+nonblock.c
+ Tests operations on non-blocking socket.
+
+op_2long.c
+ Tests PR_Open() where filename is too long.
+
+op_filnf.c
+ Tests PR_Open() where filename is NotFound.
+
+op_filok.c
+ Tests PR_Open() where filename is accessable.
+
+op_noacc.c
+ Tests PR_Open() where file permissions are wrong.
+ Limited use. Windows has no concept of Unix style file permissions.
+
+op_nofil.c
+ Tests PR_Open() where filename does not exist.
+
+parent.c
+ Test parent/child process capability
+
+perf.c
+ Tests and measures context switch times for various thread
+ syncronization functions.
+
+pipeping.c
+ Tests inter-process pipes. Run with pipepong.c
+
+pipepong.c
+ Tests inter-process pipes. Run with pipeping.c
+
+pipeself.c
+ Tests inter-thread pipes.
+
+pollable.c
+ Tests pollable events. prio.h
+
+poll_er.c
+ Tests PR_Poll() where an error is expected.
+
+poll_nm.c
+ Tests PR_Poll() where normal operation is expected.
+
+poll_to.c
+ Tests PR_Poll() where timeout is expected.
+
+prftest.c
+ Tests printf-like formatting.
+
+prftest1.c
+ Obsolete. Subsumed in prftest.c
+
+prftest2.c
+ Obsolete. Subsumed in prftest.c
+
+prfz.c
+ Tests printf handling of (s)size_t formats
+
+priotest.c
+ Limited use. Tests NSPR thread dispatching priority.
+
+provider.c
+
+prpoll.c
+ Tests PR_Poll().
+
+prselect.c
+ Obsolete. PR_Select() is obsolete.
+
+prttools.h
+ Unused file.
+
+ranfile.c
+ Tests random file access.
+
+readme
+ This file.
+
+runtests.ksh
+ A korn shell script that runs a set of tests that should run
+ on any of the NSPR supported platforms.
+
+runtests.pl
+ A perl script to run the test cases. This srcipt runs tests
+ common to all platforms and runs tests applicable to specific
+ platforms. Uses file runtests.txt to control execution.
+
+runtests.txt
+ Control file for perl script: runtests.pl
+
+rwlocktest.c
+ Tests Reader/Writer lock
+
+selct_er.c
+ Obsolete. PR_Select() is obsolete.
+
+selct_nm.c
+ Obsolete. PR_Select() is obsolete.
+
+selct_to.c
+ Obsolete. PR_Select() is obsolete.
+
+select2.c
+ Obsolete. PR_Select() is obsolete.
+
+sel_spd.c
+ Obsolete. PR_Select() is obsolete.
+
+sem.c
+ Obsolete. Semaphores are not supported.
+
+server_test.c
+ Tests sockets by simulating a server in loopback mode.
+ Makes its own client threads.
+
+servr_kk.c
+ Tests client/server sockets, threads using system threads.
+
+servr_ku.c
+ Tests client/server sockets, threads using system and user threads.
+
+servr_uk.c
+ Tests client/server sockets, threads using system and user threads.
+
+servr_uu.c
+ Tests client/server sockets, threads user threads.
+
+short_thread.c
+ Tests short-running threads. Useful for testing for race conditions.
+
+sigpipe.c
+ Tests NSPR's SIGPIPE handler. Unix only.
+
+sleep.c
+ Limited use. Tests sleep capability of platform.
+
+socket.c
+ Tests many socket functions.
+
+sockopt.c
+ Tests setting and getting socket options.
+
+sprintf.c
+ Tests sprintf.
+
+stack.c
+ Test atomic stack operations.
+
+stat.c
+ Tests performance of getfileinfo() vs. stat()
+
+stdio.c
+ Tests NSPR's handling of stdin, stdout, stderr.
+
+strod.c
+ Tests formatting of double precision floating point.
+
+suspend.c
+ Private interfaces PR_SuspendAll(), PR_ResumeAll(), etc.
+
+switch.c
+ Tests thread switching
+
+system.c
+ Tests PR_GetSystemInfo()
+
+testbit.c
+ Tests bit arrays.
+
+testfile.c
+ Tests many file I/O functions.
+
+threads.c
+ Tests thread caching.
+
+thruput.c
+ Tests socket thruput. Must be run by hand as client/server.
+ Does not self terminate.
+
+time.c
+ Incomplete. Limited use.
+
+timemac.c
+ Test time and date functions. Originally for Mac.
+
+timetest.c
+ Tests time conversion over a wide range of dates.
+
+tmoacc.c
+ Server to tmocon.c and writev.c
+ Do not run it by itself.
+
+tmocon.c
+ Client thread to tmoacc.c
+
+tpd.c
+ Tests thread private data.
+
+udpsrv.c
+ Tests UDP socket functions.
+
+ut_ttools.h
+ unused file.
+
+version.c
+ Extract and print library version data.
+
+vercheck.c
+ Test PR_VersionCheck().
+
+writev.c
+ Tests gather-write on a socket. Requires tmoacc.c
+
+xnotify.c
+ Tests cached monitors.
+
+yield.c
+ Limited use
+
+y2k.c
+ Test to verify NSPR's date functions as Y2K compliant.
+
+dll\Makefile
+ makefile for mygetval.c, mysetval.c
+
+dll\mygetval.c
+ Dynamic library test. See also dlltest.c
+
+dll\mysetval.c
+ Dynamic library test. See also dlltest.c
diff --git a/nsprpub/pr/tests/abstract.c b/nsprpub/pr/tests/abstract.c
new file mode 100644
index 0000000000..3d255c1c2b
--- /dev/null
+++ b/nsprpub/pr/tests/abstract.c
@@ -0,0 +1,157 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include <stdio.h>
+
+#if defined(LINUX)
+
+#include <string.h>
+#include "nspr.h"
+
+static const char abstractSocketName[] = "\0testsocket";
+
+static void
+ClientThread(void* aArg)
+{
+ PRFileDesc* socket;
+ PRNetAddr addr;
+ PRUint8 buf[1024];
+ PRInt32 len;
+ PRInt32 total;
+
+ addr.local.family = PR_AF_LOCAL;
+ memcpy(addr.local.path, abstractSocketName, sizeof(abstractSocketName));
+
+ socket = PR_OpenTCPSocket(addr.raw.family);
+ if (!socket) {
+ fprintf(stderr, "PR_OpenTCPSokcet failed\n");
+ exit(1);
+ }
+
+ if (PR_Connect(socket, &addr, PR_INTERVAL_NO_TIMEOUT) == PR_FAILURE) {
+ fprintf(stderr, "PR_Connect failed\n");
+ exit(1);
+ }
+
+ total = 0;
+ while (total < sizeof(buf)) {
+ len = PR_Recv(socket, buf + total, sizeof(buf) - total, 0,
+ PR_INTERVAL_NO_TIMEOUT);
+ if (len < 1) {
+ fprintf(stderr, "PR_Recv failed\n");
+ exit(1);
+ }
+ total += len;
+ }
+
+ total = 0;
+ while (total < sizeof(buf)) {
+ len = PR_Send(socket, buf + total, sizeof(buf) - total, 0,
+ PR_INTERVAL_NO_TIMEOUT);
+ if (len < 1) {
+ fprintf(stderr, "PR_Send failed\n");
+ exit(1);
+ }
+ total += len;
+ }
+
+ if (PR_Close(socket) == PR_FAILURE) {
+ fprintf(stderr, "PR_Close failed\n");
+ exit(1);
+ }
+}
+
+int
+main()
+{
+ PRFileDesc* socket;
+ PRFileDesc* acceptSocket;
+ PRThread* thread;
+ PRNetAddr addr;
+ PRUint8 buf[1024];
+ PRInt32 len;
+ PRInt32 total;
+
+ addr.local.family = PR_AF_LOCAL;
+ memcpy(addr.local.path, abstractSocketName, sizeof(abstractSocketName));
+
+ socket = PR_OpenTCPSocket(addr.raw.family);
+ if (!socket) {
+ fprintf(stderr, "PR_OpenTCPSocket failed\n");
+ exit(1);
+ }
+ if (PR_Bind(socket, &addr) == PR_FAILURE) {
+ fprintf(stderr, "PR_Bind failed\n");
+ exit(1);
+ }
+
+ if (PR_Listen(socket, 5) == PR_FAILURE) {
+ fprintf(stderr, "PR_Listen failed\n");
+ exit(1);
+ }
+
+ thread = PR_CreateThread(PR_USER_THREAD, ClientThread, 0, PR_PRIORITY_NORMAL,
+ PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0);
+ if (!thread) {
+ fprintf(stderr, "PR_CreateThread failed");
+ exit(1);
+ }
+
+ acceptSocket = PR_Accept(socket, NULL, PR_INTERVAL_NO_TIMEOUT);
+ if (!acceptSocket) {
+ fprintf(stderr, "PR_Accept failed\n");
+ exit(1);
+ }
+
+ memset(buf, 'A', sizeof(buf));
+
+ total = 0;
+ while (total < sizeof(buf)) {
+ len = PR_Send(acceptSocket, buf + total, sizeof(buf) - total, 0,
+ PR_INTERVAL_NO_TIMEOUT);
+ if (len < 1) {
+ fprintf(stderr, "PR_Send failed\n");
+ exit(1);
+ }
+ total += len;
+ }
+
+ total = 0;
+ while (total < sizeof(buf)) {
+ len = PR_Recv(acceptSocket, buf + total, sizeof(buf) - total, 0,
+ PR_INTERVAL_NO_TIMEOUT);
+ if (len < 1) {
+ fprintf(stderr, "PR_Recv failed\n");
+ exit(1);
+ }
+ total += len;
+ }
+
+ if (PR_Close(acceptSocket) == PR_FAILURE) {
+ fprintf(stderr, "PR_Close failed\n");
+ exit(1);
+ }
+
+ if (PR_JoinThread(thread) == PR_FAILURE) {
+ fprintf(stderr, "PR_JoinThread failed\n");
+ exit(1);
+ }
+
+ if (PR_Close(socket) == PR_FAILURE) {
+ fprintf(stderr, "PR_Close failed\n");
+ exit(1);
+ }
+ printf("PASS\n");
+ return 0;
+}
+
+#else
+int
+main()
+{
+ printf("PASS\n");
+ return 0;
+}
+#endif
diff --git a/nsprpub/pr/tests/accept.c b/nsprpub/pr/tests/accept.c
new file mode 100644
index 0000000000..3e3850b698
--- /dev/null
+++ b/nsprpub/pr/tests/accept.c
@@ -0,0 +1,508 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/***********************************************************************
+** 1996 - Netscape Communications Corporation
+**
+** Name: accept.c
+**
+** Description: Run accept() sucessful connection tests.
+**
+** Modification History:
+** 04-Jun-97 AGarcia - Reconvert test file to return a 0 for PASS and a 1 for FAIL
+** 13-May-97 AGarcia- Converted the test to accomodate the debug_mode
+** The debug mode will print all of the printfs associated with this test.
+** The regress mode will be the default mode. Since the regress tool limits
+** the output to a one line status:PASS or FAIL,all of the printf statements
+** have been handled with an if (debug_mode) statement.
+** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to
+** recognize the return code from tha main program.
+** 12-June-97 Revert to return code 0 and 1.
+***********************************************************************/
+
+/***********************************************************************
+** Includes
+***********************************************************************/
+
+#include "nspr.h"
+#include "prpriv.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "plgetopt.h"
+#include "plerror.h"
+
+#define BASE_PORT 10000
+
+#define CLIENT_DATA 128
+
+#define ACCEPT_NORMAL 0x1
+#define ACCEPT_FAST 0x2
+#define ACCEPT_READ 0x3
+#define ACCEPT_READ_FAST 0x4
+#define ACCEPT_READ_FAST_CB 0x5
+
+#define CLIENT_NORMAL 0x1
+#define CLIENT_TIMEOUT_ACCEPT 0x2
+#define CLIENT_TIMEOUT_SEND 0x3
+
+#define SERVER_MAX_BIND_COUNT 100
+
+#if defined(XP_OS2)
+#define TIMEOUTSECS 10
+#else
+#define TIMEOUTSECS 2
+#endif
+PRIntervalTime timeoutTime;
+
+static PRInt32 count = 1;
+static PRFileDesc *output;
+static PRNetAddr serverAddr;
+static PRThreadScope thread_scope = PR_LOCAL_THREAD;
+static PRInt32 clientCommand;
+static PRInt32 iterations;
+static PRStatus rv;
+static PRFileDesc *listenSock;
+static PRFileDesc *clientSock = NULL;
+static PRNetAddr listenAddr;
+static PRNetAddr clientAddr;
+static PRThread *clientThread;
+static PRNetAddr *raddr;
+static char buf[4096 + 2*sizeof(PRNetAddr) + 32];
+static PRInt32 status;
+static PRInt32 bytesRead;
+
+PRIntn failed_already=0;
+PRIntn debug_mode;
+
+void Test_Assert(const char *msg, const char *file, PRIntn line)
+{
+ failed_already=1;
+ if (debug_mode) {
+ PR_fprintf(output, "@%s:%d ", file, line);
+ PR_fprintf(output, msg);
+ }
+} /* Test_Assert */
+
+#define TEST_ASSERT(expr) \
+ if (!(expr)) Test_Assert(#expr, __FILE__, __LINE__)
+
+#ifdef WINNT
+#define CALLBACK_MAGIC 0x12345678
+
+void timeout_callback(void *magic)
+{
+ TEST_ASSERT(magic == (void *)CALLBACK_MAGIC);
+ if (debug_mode) {
+ PR_fprintf(output, "timeout callback called okay\n");
+ }
+}
+#endif
+
+
+static void PR_CALLBACK
+ClientThread(void *_action)
+{
+ PRInt32 action = * (PRInt32 *) _action;
+ PRInt32 iterations = count;
+ PRFileDesc *sock = NULL;
+
+ serverAddr.inet.family = PR_AF_INET;
+ serverAddr.inet.port = listenAddr.inet.port;
+ serverAddr.inet.ip = PR_htonl(PR_INADDR_LOOPBACK);
+
+ for (; iterations--;) {
+ PRInt32 rv;
+ char buf[CLIENT_DATA];
+
+ memset(buf, 0xaf, sizeof(buf)); /* initialize with arbitrary data */
+ sock = PR_NewTCPSocket();
+ if (!sock) {
+ if (!debug_mode) {
+ failed_already=1;
+ }
+ else {
+ PR_fprintf(output, "client: unable to create socket\n");
+ }
+ return;
+ }
+
+ if (action != CLIENT_TIMEOUT_ACCEPT) {
+
+ if ((rv = PR_Connect(sock, &serverAddr,
+ timeoutTime)) < 0) {
+ if (!debug_mode) {
+ failed_already=1;
+ }
+ else
+ PR_fprintf(output,
+ "client: unable to connect to server (%ld, %ld, %ld, %ld)\n",
+ iterations, rv, PR_GetError(), PR_GetOSError());
+ goto ErrorExit;
+ }
+
+ if (action != CLIENT_TIMEOUT_SEND) {
+ if ((rv = PR_Send(sock, buf, CLIENT_DATA,
+ 0, timeoutTime))< 0) {
+ if (!debug_mode) {
+ failed_already=1;
+ } else {
+ PR_fprintf(output,
+ "client: unable to send to server (%d, %ld, %ld)\n",
+ CLIENT_DATA, rv, PR_GetError());
+ }
+ goto ErrorExit;
+ }
+ } else {
+ PR_Sleep(PR_SecondsToInterval(TIMEOUTSECS + 1));
+ }
+ } else {
+ PR_Sleep(PR_SecondsToInterval(TIMEOUTSECS + 1));
+ }
+ if (debug_mode) {
+ PR_fprintf(output, ".");
+ }
+ PR_Close(sock);
+ sock = NULL;
+ }
+ if (debug_mode) {
+ PR_fprintf(output, "\n");
+ }
+
+ErrorExit:
+ if (sock != NULL) {
+ PR_Close(sock);
+ }
+}
+
+
+static void
+RunTest(PRInt32 acceptType, PRInt32 clientAction)
+{
+ int i;
+
+ /* First bind to the socket */
+ listenSock = PR_NewTCPSocket();
+ if (!listenSock) {
+ failed_already=1;
+ if (debug_mode) {
+ PR_fprintf(output, "unable to create listen socket\n");
+ }
+ return;
+ }
+ memset(&listenAddr, 0, sizeof(listenAddr));
+ listenAddr.inet.family = PR_AF_INET;
+ listenAddr.inet.port = PR_htons(BASE_PORT);
+ listenAddr.inet.ip = PR_htonl(PR_INADDR_ANY);
+ /*
+ * try a few times to bind server's address, if addresses are in
+ * use
+ */
+ i = 0;
+ while (PR_Bind(listenSock, &listenAddr) == PR_FAILURE) {
+ if (PR_GetError() == PR_ADDRESS_IN_USE_ERROR) {
+ listenAddr.inet.port += 2;
+ if (i++ < SERVER_MAX_BIND_COUNT) {
+ continue;
+ }
+ }
+ failed_already=1;
+ if (debug_mode) {
+ PR_fprintf(output,"accept: ERROR - PR_Bind failed\n");
+ }
+ return;
+ }
+
+
+ rv = PR_Listen(listenSock, 100);
+ if (rv == PR_FAILURE) {
+ failed_already=1;
+ if (debug_mode) {
+ PR_fprintf(output, "unable to listen\n");
+ }
+ return;
+ }
+
+ clientCommand = clientAction;
+ clientThread = PR_CreateThread(PR_USER_THREAD, ClientThread,
+ (void *)&clientCommand, PR_PRIORITY_NORMAL, thread_scope,
+ PR_JOINABLE_THREAD, 0);
+ if (!clientThread) {
+ failed_already=1;
+ if (debug_mode) {
+ PR_fprintf(output, "error creating client thread\n");
+ }
+ return;
+ }
+
+ iterations = count;
+ for (; iterations--;) {
+ switch (acceptType) {
+ case ACCEPT_NORMAL:
+ clientSock = PR_Accept(listenSock, &clientAddr,
+ timeoutTime);
+ switch(clientAction) {
+ case CLIENT_TIMEOUT_ACCEPT:
+ TEST_ASSERT(clientSock == 0);
+ TEST_ASSERT(PR_GetError() == PR_IO_TIMEOUT_ERROR);
+ break;
+ case CLIENT_NORMAL:
+ TEST_ASSERT(clientSock);
+ bytesRead = PR_Recv(clientSock,
+ buf, CLIENT_DATA, 0, timeoutTime);
+ TEST_ASSERT(bytesRead == CLIENT_DATA);
+ break;
+ case CLIENT_TIMEOUT_SEND:
+ TEST_ASSERT(clientSock);
+ bytesRead = PR_Recv(clientSock,
+ buf, CLIENT_DATA, 0, timeoutTime);
+ TEST_ASSERT(bytesRead == -1);
+ TEST_ASSERT(PR_GetError() == PR_IO_TIMEOUT_ERROR);
+ break;
+ }
+ break;
+ case ACCEPT_READ:
+ status = PR_AcceptRead(listenSock, &clientSock,
+ &raddr, buf, CLIENT_DATA, timeoutTime);
+ switch(clientAction) {
+ case CLIENT_TIMEOUT_ACCEPT:
+ /* Invalid test case */
+ TEST_ASSERT(0);
+ break;
+ case CLIENT_NORMAL:
+ TEST_ASSERT(clientSock);
+ TEST_ASSERT(status == CLIENT_DATA);
+ break;
+ case CLIENT_TIMEOUT_SEND:
+ TEST_ASSERT(status == -1);
+ TEST_ASSERT(PR_GetError() == PR_IO_TIMEOUT_ERROR);
+ break;
+ }
+ break;
+#ifdef WINNT
+ case ACCEPT_FAST:
+ clientSock = PR_NTFast_Accept(listenSock,
+ &clientAddr, timeoutTime);
+ switch(clientAction) {
+ case CLIENT_TIMEOUT_ACCEPT:
+ TEST_ASSERT(clientSock == 0);
+ if (debug_mode) {
+ PR_fprintf(output, "PR_GetError is %ld\n", PR_GetError());
+ }
+ TEST_ASSERT(PR_GetError() == PR_IO_TIMEOUT_ERROR);
+ break;
+ case CLIENT_NORMAL:
+ TEST_ASSERT(clientSock);
+ bytesRead = PR_Recv(clientSock,
+ buf, CLIENT_DATA, 0, timeoutTime);
+ TEST_ASSERT(bytesRead == CLIENT_DATA);
+ break;
+ case CLIENT_TIMEOUT_SEND:
+ TEST_ASSERT(clientSock);
+ bytesRead = PR_Recv(clientSock,
+ buf, CLIENT_DATA, 0, timeoutTime);
+ TEST_ASSERT(bytesRead == -1);
+ TEST_ASSERT(PR_GetError() == PR_IO_TIMEOUT_ERROR);
+ break;
+ }
+ break;
+ break;
+ case ACCEPT_READ_FAST:
+ status = PR_NTFast_AcceptRead(listenSock,
+ &clientSock, &raddr, buf, 4096, timeoutTime);
+ switch(clientAction) {
+ case CLIENT_TIMEOUT_ACCEPT:
+ /* Invalid test case */
+ TEST_ASSERT(0);
+ break;
+ case CLIENT_NORMAL:
+ TEST_ASSERT(clientSock);
+ TEST_ASSERT(status == CLIENT_DATA);
+ break;
+ case CLIENT_TIMEOUT_SEND:
+ TEST_ASSERT(clientSock == NULL);
+ TEST_ASSERT(status == -1);
+ TEST_ASSERT(PR_GetError() == PR_IO_TIMEOUT_ERROR);
+ break;
+ }
+ break;
+ case ACCEPT_READ_FAST_CB:
+ status = PR_NTFast_AcceptRead_WithTimeoutCallback(
+ listenSock, &clientSock, &raddr, buf, 4096,
+ timeoutTime, timeout_callback, (void *)CALLBACK_MAGIC);
+ switch(clientAction) {
+ case CLIENT_TIMEOUT_ACCEPT:
+ /* Invalid test case */
+ TEST_ASSERT(0);
+ break;
+ case CLIENT_NORMAL:
+ TEST_ASSERT(clientSock);
+ TEST_ASSERT(status == CLIENT_DATA);
+ break;
+ case CLIENT_TIMEOUT_SEND:
+ if (debug_mode) {
+ PR_fprintf(output, "clientSock = 0x%8.8lx\n", clientSock);
+ }
+ TEST_ASSERT(clientSock == NULL);
+ TEST_ASSERT(status == -1);
+ TEST_ASSERT(PR_GetError() == PR_IO_TIMEOUT_ERROR);
+ break;
+ }
+ break;
+#endif
+ }
+ if (clientSock != NULL) {
+ PR_Close(clientSock);
+ clientSock = NULL;
+ }
+ }
+ PR_Close(listenSock);
+
+ PR_JoinThread(clientThread);
+}
+
+
+void AcceptUpdatedTest(void)
+{
+ RunTest(ACCEPT_NORMAL, CLIENT_NORMAL);
+}
+void AcceptNotUpdatedTest(void)
+{
+ RunTest(ACCEPT_FAST, CLIENT_NORMAL);
+}
+void AcceptReadTest(void)
+{
+ RunTest(ACCEPT_READ, CLIENT_NORMAL);
+}
+void AcceptReadNotUpdatedTest(void)
+{
+ RunTest(ACCEPT_READ_FAST, CLIENT_NORMAL);
+}
+void AcceptReadCallbackTest(void)
+{
+ RunTest(ACCEPT_READ_FAST_CB, CLIENT_NORMAL);
+}
+
+void TimeoutAcceptUpdatedTest(void)
+{
+ RunTest(ACCEPT_NORMAL, CLIENT_TIMEOUT_ACCEPT);
+}
+void TimeoutAcceptNotUpdatedTest(void)
+{
+ RunTest(ACCEPT_FAST, CLIENT_TIMEOUT_ACCEPT);
+}
+void TimeoutAcceptReadCallbackTest(void)
+{
+ RunTest(ACCEPT_READ_FAST_CB, CLIENT_TIMEOUT_ACCEPT);
+}
+
+void TimeoutReadUpdatedTest(void)
+{
+ RunTest(ACCEPT_NORMAL, CLIENT_TIMEOUT_SEND);
+}
+void TimeoutReadNotUpdatedTest(void)
+{
+ RunTest(ACCEPT_FAST, CLIENT_TIMEOUT_SEND);
+}
+void TimeoutReadReadTest(void)
+{
+ RunTest(ACCEPT_READ, CLIENT_TIMEOUT_SEND);
+}
+void TimeoutReadReadNotUpdatedTest(void)
+{
+ RunTest(ACCEPT_READ_FAST, CLIENT_TIMEOUT_SEND);
+}
+void TimeoutReadReadCallbackTest(void)
+{
+ RunTest(ACCEPT_READ_FAST_CB, CLIENT_TIMEOUT_SEND);
+}
+
+/************************************************************************/
+
+static void Measure(void (*func)(void), const char *msg)
+{
+ PRIntervalTime start, stop;
+ double d;
+
+ start = PR_IntervalNow();
+ (*func)();
+ stop = PR_IntervalNow();
+
+ d = (double)PR_IntervalToMicroseconds(stop - start);
+ if (debug_mode) {
+ PR_fprintf(output, "%40s: %6.2f usec\n", msg, d / count);
+ }
+
+}
+
+int main(int argc, char **argv)
+{
+
+ /* The command line argument: -d is used to determine if the test is being run
+ in debug mode. The regress tool requires only one line output:PASS or FAIL.
+ All of the printfs associated with this test has been handled with a if (debug_mode)
+ test.
+ Usage: test_name [-d] [-c n]
+ */
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "Gdc:");
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 'G': /* global threads */
+ thread_scope = PR_GLOBAL_THREAD;
+ break;
+ case 'd': /* debug mode */
+ debug_mode = 1;
+ break;
+ case 'c': /* loop counter */
+ count = atoi(opt->value);
+ break;
+ default:
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
+ output = PR_STDERR;
+ PR_STDIO_INIT();
+
+ timeoutTime = PR_SecondsToInterval(TIMEOUTSECS);
+ if (debug_mode) {
+ PR_fprintf(output, "\nRun accept() sucessful connection tests\n");
+ }
+
+ Measure(AcceptUpdatedTest, "PR_Accept()");
+ Measure(AcceptReadTest, "PR_AcceptRead()");
+#ifdef WINNT
+ Measure(AcceptNotUpdatedTest, "PR_NTFast_Accept()");
+ Measure(AcceptReadNotUpdatedTest, "PR_NTFast_AcceptRead()");
+ Measure(AcceptReadCallbackTest, "PR_NTFast_AcceptRead_WithTimeoutCallback()");
+#endif
+ if (debug_mode) {
+ PR_fprintf(output, "\nRun accept() timeout in the accept tests\n");
+ }
+#ifdef WINNT
+ Measure(TimeoutReadReadCallbackTest, "PR_NTFast_AcceptRead_WithTimeoutCallback()");
+#endif
+ Measure(TimeoutReadUpdatedTest, "PR_Accept()");
+ if (debug_mode) {
+ PR_fprintf(output, "\nRun accept() timeout in the read tests\n");
+ }
+ Measure(TimeoutReadReadTest, "PR_AcceptRead()");
+#ifdef WINNT
+ Measure(TimeoutReadNotUpdatedTest, "PR_NTFast_Accept()");
+ Measure(TimeoutReadReadNotUpdatedTest, "PR_NTFast_AcceptRead()");
+ Measure(TimeoutReadReadCallbackTest, "PR_NTFast_AcceptRead_WithTimeoutCallback()");
+#endif
+ PR_fprintf(output, "%s\n", (failed_already) ? "FAIL" : "PASS");
+ return failed_already;
+}
diff --git a/nsprpub/pr/tests/acceptread.c b/nsprpub/pr/tests/acceptread.c
new file mode 100644
index 0000000000..090b084555
--- /dev/null
+++ b/nsprpub/pr/tests/acceptread.c
@@ -0,0 +1,270 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include <prio.h>
+#include <prprf.h>
+#include <prinit.h>
+#include <prnetdb.h>
+#include <prinrval.h>
+#include <prthread.h>
+
+#include <plerror.h>
+
+#include <stdlib.h>
+
+#ifdef DEBUG
+#define PORT_INC_DO +100
+#else
+#define PORT_INC_DO
+#endif
+#ifdef IS_64
+#define PORT_INC_3264 +200
+#else
+#define PORT_INC_3264
+#endif
+
+#define DEFAULT_PORT 12273 PORT_INC_DO PORT_INC_3264
+#define GET "GET / HTTP/1.0\n\n"
+static PRFileDesc *std_out, *err_out;
+static PRIntervalTime write_dally, accept_timeout;
+
+static PRStatus PrintAddress(const PRNetAddr* address)
+{
+ char buffer[100];
+ PRStatus rv = PR_NetAddrToString(address, buffer, sizeof(buffer));
+ if (PR_FAILURE == rv) {
+ PL_FPrintError(err_out, "PR_NetAddrToString");
+ }
+ else PR_fprintf(
+ std_out, "Accepted connection from (0x%p)%s:%d\n",
+ address, buffer, address->inet.port);
+ return rv;
+} /* PrintAddress */
+
+static void ConnectingThread(void *arg)
+{
+ PRInt32 nbytes;
+ char buf[1024];
+ PRFileDesc *sock;
+ PRNetAddr peer_addr, *addr;
+
+ addr = (PRNetAddr*)arg;
+
+ sock = PR_NewTCPSocket();
+ if (sock == NULL)
+ {
+ PL_FPrintError(err_out, "PR_NewTCPSocket (client) failed");
+ PR_ProcessExit(1);
+ }
+
+ if (PR_Connect(sock, addr, PR_INTERVAL_NO_TIMEOUT) == PR_FAILURE)
+ {
+ PL_FPrintError(err_out, "PR_Connect (client) failed");
+ PR_ProcessExit(1);
+ }
+ if (PR_GetPeerName(sock, &peer_addr) == PR_FAILURE)
+ {
+ PL_FPrintError(err_out, "PR_GetPeerName (client) failed");
+ PR_ProcessExit(1);
+ }
+
+ /*
+ ** Then wait between the connection coming up and sending the expected
+ ** data. At some point in time, the server should fail due to a timeou
+ ** on the AcceptRead() operation, which according to the document is
+ ** only due to the read() portion.
+ */
+ PR_Sleep(write_dally);
+
+ nbytes = PR_Send(sock, GET, sizeof(GET), 0, PR_INTERVAL_NO_TIMEOUT);
+ if (nbytes == -1) {
+ PL_FPrintError(err_out, "PR_Send (client) failed");
+ }
+
+ nbytes = PR_Recv(sock, buf, sizeof(buf), 0, PR_INTERVAL_NO_TIMEOUT);
+ if (nbytes == -1) {
+ PL_FPrintError(err_out, "PR_Recv (client) failed");
+ }
+ else
+ {
+ PR_fprintf(std_out, "PR_Recv (client) succeeded: %d bytes\n", nbytes);
+ buf[sizeof(buf) - 1] = '\0';
+ PR_fprintf(std_out, "%s\n", buf);
+ }
+
+ if (PR_FAILURE == PR_Shutdown(sock, PR_SHUTDOWN_BOTH)) {
+ PL_FPrintError(err_out, "PR_Shutdown (client) failed");
+ }
+
+ if (PR_FAILURE == PR_Close(sock)) {
+ PL_FPrintError(err_out, "PR_Close (client) failed");
+ }
+
+ return;
+} /* ConnectingThread */
+
+#define BUF_SIZE 117
+static void AcceptingThread(void *arg)
+{
+ PRStatus rv;
+ PRInt32 bytes;
+ PRSize buf_size = BUF_SIZE;
+ PRUint8 buf[BUF_SIZE + (2 * sizeof(PRNetAddr)) + 32];
+ PRNetAddr *accept_addr, *listen_addr = (PRNetAddr*)arg;
+ PRFileDesc *accept_sock, *listen_sock = PR_NewTCPSocket();
+ PRSocketOptionData sock_opt;
+
+ if (NULL == listen_sock)
+ {
+ PL_FPrintError(err_out, "PR_NewTCPSocket (server) failed");
+ PR_ProcessExit(1);
+ }
+ sock_opt.option = PR_SockOpt_Reuseaddr;
+ sock_opt.value.reuse_addr = PR_TRUE;
+ rv = PR_SetSocketOption(listen_sock, &sock_opt);
+ if (PR_FAILURE == rv)
+ {
+ PL_FPrintError(err_out, "PR_SetSocketOption (server) failed");
+ PR_ProcessExit(1);
+ }
+ rv = PR_Bind(listen_sock, listen_addr);
+ if (PR_FAILURE == rv)
+ {
+ PL_FPrintError(err_out, "PR_Bind (server) failed");
+ PR_ProcessExit(1);
+ }
+ rv = PR_Listen(listen_sock, 10);
+ if (PR_FAILURE == rv)
+ {
+ PL_FPrintError(err_out, "PR_Listen (server) failed");
+ PR_ProcessExit(1);
+ }
+ bytes = PR_AcceptRead(
+ listen_sock, &accept_sock, &accept_addr, buf, buf_size, accept_timeout);
+
+ if (-1 == bytes) {
+ PL_FPrintError(err_out, "PR_AcceptRead (server) failed");
+ }
+ else
+ {
+ PrintAddress(accept_addr);
+ PR_fprintf(
+ std_out, "(Server) read [0x%p..0x%p) %s\n",
+ buf, &buf[BUF_SIZE], buf);
+ bytes = PR_Write(accept_sock, buf, bytes);
+ rv = PR_Shutdown(accept_sock, PR_SHUTDOWN_BOTH);
+ if (PR_FAILURE == rv) {
+ PL_FPrintError(err_out, "PR_Shutdown (server) failed");
+ }
+ }
+
+ if (-1 != bytes)
+ {
+ rv = PR_Close(accept_sock);
+ if (PR_FAILURE == rv) {
+ PL_FPrintError(err_out, "PR_Close (server) failed");
+ }
+ }
+
+ rv = PR_Close(listen_sock);
+ if (PR_FAILURE == rv) {
+ PL_FPrintError(err_out, "PR_Close (server) failed");
+ }
+} /* AcceptingThread */
+
+int main(int argc, char **argv)
+{
+ PRHostEnt he;
+ PRStatus status;
+ PRIntn next_index;
+ PRUint16 port_number;
+ char netdb_buf[PR_NETDB_BUF_SIZE];
+ PRNetAddr client_addr, server_addr;
+ PRThread *client_thread, *server_thread;
+ PRIntervalTime delta = PR_MillisecondsToInterval(500);
+
+ err_out = PR_STDERR;
+ std_out = PR_STDOUT;
+ accept_timeout = PR_SecondsToInterval(2);
+
+ if (argc != 2 && argc != 3) {
+ port_number = DEFAULT_PORT;
+ }
+ else {
+ port_number = (PRUint16)atoi(argv[(argc == 2) ? 1 : 2]);
+ }
+
+ status = PR_InitializeNetAddr(PR_IpAddrAny, port_number, &server_addr);
+ if (PR_SUCCESS != status)
+ {
+ PL_FPrintError(err_out, "PR_InitializeNetAddr failed");
+ PR_ProcessExit(1);
+ }
+ if (argc < 3)
+ {
+ status = PR_InitializeNetAddr(
+ PR_IpAddrLoopback, port_number, &client_addr);
+ if (PR_SUCCESS != status)
+ {
+ PL_FPrintError(err_out, "PR_InitializeNetAddr failed");
+ PR_ProcessExit(1);
+ }
+ }
+ else
+ {
+ status = PR_GetHostByName(
+ argv[1], netdb_buf, sizeof(netdb_buf), &he);
+ if (status == PR_FAILURE)
+ {
+ PL_FPrintError(err_out, "PR_GetHostByName failed");
+ PR_ProcessExit(1);
+ }
+ next_index = PR_EnumerateHostEnt(0, &he, port_number, &client_addr);
+ if (next_index == -1)
+ {
+ PL_FPrintError(err_out, "PR_EnumerateHostEnt failed");
+ PR_ProcessExit(1);
+ }
+ }
+
+ for (
+ write_dally = 0;
+ write_dally < accept_timeout + (2 * delta);
+ write_dally += delta)
+ {
+ PR_fprintf(
+ std_out, "Testing w/ write_dally = %d msec\n",
+ PR_IntervalToMilliseconds(write_dally));
+ server_thread = PR_CreateThread(
+ PR_USER_THREAD, AcceptingThread, &server_addr,
+ PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0);
+ if (server_thread == NULL)
+ {
+ PL_FPrintError(err_out, "PR_CreateThread (server) failed");
+ PR_ProcessExit(1);
+ }
+
+ PR_Sleep(delta); /* let the server pot thicken */
+
+ client_thread = PR_CreateThread(
+ PR_USER_THREAD, ConnectingThread, &client_addr,
+ PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0);
+ if (client_thread == NULL)
+ {
+ PL_FPrintError(err_out, "PR_CreateThread (client) failed");
+ PR_ProcessExit(1);
+ }
+
+ if (PR_JoinThread(client_thread) == PR_FAILURE) {
+ PL_FPrintError(err_out, "PR_JoinThread (client) failed");
+ }
+
+ if (PR_JoinThread(server_thread) == PR_FAILURE) {
+ PL_FPrintError(err_out, "PR_JoinThread (server) failed");
+ }
+ }
+
+ return 0;
+}
diff --git a/nsprpub/pr/tests/acceptreademu.c b/nsprpub/pr/tests/acceptreademu.c
new file mode 100644
index 0000000000..485b9d5025
--- /dev/null
+++ b/nsprpub/pr/tests/acceptreademu.c
@@ -0,0 +1,300 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * This test is the same as acceptread.c except that it uses the
+ * emulated acceptread method instead of the regular acceptread.
+ */
+
+#include <prio.h>
+#include <prprf.h>
+#include <prinit.h>
+#include <prnetdb.h>
+#include <prinrval.h>
+#include <prthread.h>
+#include <pprio.h>
+
+#include <plerror.h>
+
+#include <stdlib.h>
+
+#ifdef DEBUG
+#define PORT_INC_DO +100
+#else
+#define PORT_INC_DO
+#endif
+#ifdef IS_64
+#define PORT_INC_3264 +200
+#else
+#define PORT_INC_3264
+#endif
+
+#define DEFAULT_PORT 12273 PORT_INC_DO PORT_INC_3264
+#define GET "GET / HTTP/1.0\n\n"
+static PRFileDesc *std_out, *err_out;
+static PRIntervalTime write_dally, accept_timeout;
+static PRDescIdentity emu_layer_ident;
+static PRIOMethods emu_layer_methods;
+
+/* the acceptread method in emu_layer_methods */
+static PRInt32 PR_CALLBACK emu_AcceptRead(PRFileDesc *sd, PRFileDesc **nd,
+ PRNetAddr **raddr, void *buf, PRInt32 amount, PRIntervalTime timeout)
+{
+ return PR_EmulateAcceptRead(sd, nd, raddr, buf, amount, timeout);
+}
+
+static PRStatus PrintAddress(const PRNetAddr* address)
+{
+ char buffer[100];
+ PRStatus rv = PR_NetAddrToString(address, buffer, sizeof(buffer));
+ if (PR_FAILURE == rv) {
+ PL_FPrintError(err_out, "PR_NetAddrToString");
+ }
+ else PR_fprintf(
+ std_out, "Accepted connection from (0x%p)%s:%d\n",
+ address, buffer, address->inet.port);
+ return rv;
+} /* PrintAddress */
+
+static void ConnectingThread(void *arg)
+{
+ PRInt32 nbytes;
+ char buf[1024];
+ PRFileDesc *sock;
+ PRNetAddr peer_addr, *addr;
+
+ addr = (PRNetAddr*)arg;
+
+ sock = PR_NewTCPSocket();
+ if (sock == NULL)
+ {
+ PL_FPrintError(err_out, "PR_NewTCPSocket (client) failed");
+ PR_ProcessExit(1);
+ }
+
+ if (PR_Connect(sock, addr, PR_INTERVAL_NO_TIMEOUT) == PR_FAILURE)
+ {
+ PL_FPrintError(err_out, "PR_Connect (client) failed");
+ PR_ProcessExit(1);
+ }
+ if (PR_GetPeerName(sock, &peer_addr) == PR_FAILURE)
+ {
+ PL_FPrintError(err_out, "PR_GetPeerName (client) failed");
+ PR_ProcessExit(1);
+ }
+
+ /*
+ ** Then wait between the connection coming up and sending the expected
+ ** data. At some point in time, the server should fail due to a timeou
+ ** on the AcceptRead() operation, which according to the document is
+ ** only due to the read() portion.
+ */
+ PR_Sleep(write_dally);
+
+ nbytes = PR_Send(sock, GET, sizeof(GET), 0, PR_INTERVAL_NO_TIMEOUT);
+ if (nbytes == -1) {
+ PL_FPrintError(err_out, "PR_Send (client) failed");
+ }
+
+ nbytes = PR_Recv(sock, buf, sizeof(buf), 0, PR_INTERVAL_NO_TIMEOUT);
+ if (nbytes == -1) {
+ PL_FPrintError(err_out, "PR_Recv (client) failed");
+ }
+ else
+ {
+ PR_fprintf(std_out, "PR_Recv (client) succeeded: %d bytes\n", nbytes);
+ buf[sizeof(buf) - 1] = '\0';
+ PR_fprintf(std_out, "%s\n", buf);
+ }
+
+ if (PR_FAILURE == PR_Shutdown(sock, PR_SHUTDOWN_BOTH)) {
+ PL_FPrintError(err_out, "PR_Shutdown (client) failed");
+ }
+
+ if (PR_FAILURE == PR_Close(sock)) {
+ PL_FPrintError(err_out, "PR_Close (client) failed");
+ }
+
+ return;
+} /* ConnectingThread */
+
+#define BUF_SIZE 117
+static void AcceptingThread(void *arg)
+{
+ PRStatus rv;
+ PRInt32 bytes;
+ PRSize buf_size = BUF_SIZE;
+ PRUint8 buf[BUF_SIZE + (2 * sizeof(PRNetAddr)) + 32];
+ PRNetAddr *accept_addr, *listen_addr = (PRNetAddr*)arg;
+ PRFileDesc *accept_sock, *listen_sock = PR_NewTCPSocket();
+ PRFileDesc *layer;
+ PRSocketOptionData sock_opt;
+
+ if (NULL == listen_sock)
+ {
+ PL_FPrintError(err_out, "PR_NewTCPSocket (server) failed");
+ PR_ProcessExit(1);
+ }
+ layer = PR_CreateIOLayerStub(emu_layer_ident, &emu_layer_methods);
+ if (NULL == layer)
+ {
+ PL_FPrintError(err_out, "PR_CreateIOLayerStub (server) failed");
+ PR_ProcessExit(1);
+ }
+ if (PR_PushIOLayer(listen_sock, PR_TOP_IO_LAYER, layer) == PR_FAILURE)
+ {
+ PL_FPrintError(err_out, "PR_PushIOLayer (server) failed");
+ PR_ProcessExit(1);
+ }
+ sock_opt.option = PR_SockOpt_Reuseaddr;
+ sock_opt.value.reuse_addr = PR_TRUE;
+ rv = PR_SetSocketOption(listen_sock, &sock_opt);
+ if (PR_FAILURE == rv)
+ {
+ PL_FPrintError(err_out, "PR_SetSocketOption (server) failed");
+ PR_ProcessExit(1);
+ }
+ rv = PR_Bind(listen_sock, listen_addr);
+ if (PR_FAILURE == rv)
+ {
+ PL_FPrintError(err_out, "PR_Bind (server) failed");
+ PR_ProcessExit(1);
+ }
+ rv = PR_Listen(listen_sock, 10);
+ if (PR_FAILURE == rv)
+ {
+ PL_FPrintError(err_out, "PR_Listen (server) failed");
+ PR_ProcessExit(1);
+ }
+ bytes = PR_AcceptRead(
+ listen_sock, &accept_sock, &accept_addr, buf, buf_size, accept_timeout);
+
+ if (-1 == bytes) {
+ PL_FPrintError(err_out, "PR_AcceptRead (server) failed");
+ }
+ else
+ {
+ PrintAddress(accept_addr);
+ PR_fprintf(
+ std_out, "(Server) read [0x%p..0x%p) %s\n",
+ buf, &buf[BUF_SIZE], buf);
+ bytes = PR_Write(accept_sock, buf, bytes);
+ rv = PR_Shutdown(accept_sock, PR_SHUTDOWN_BOTH);
+ if (PR_FAILURE == rv) {
+ PL_FPrintError(err_out, "PR_Shutdown (server) failed");
+ }
+ }
+
+ if (-1 != bytes)
+ {
+ rv = PR_Close(accept_sock);
+ if (PR_FAILURE == rv) {
+ PL_FPrintError(err_out, "PR_Close (server) failed");
+ }
+ }
+
+ rv = PR_Close(listen_sock);
+ if (PR_FAILURE == rv) {
+ PL_FPrintError(err_out, "PR_Close (server) failed");
+ }
+} /* AcceptingThread */
+
+int main(int argc, char **argv)
+{
+ PRHostEnt he;
+ PRStatus status;
+ PRIntn next_index;
+ PRUint16 port_number;
+ char netdb_buf[PR_NETDB_BUF_SIZE];
+ PRNetAddr client_addr, server_addr;
+ PRThread *client_thread, *server_thread;
+ PRIntervalTime delta = PR_MillisecondsToInterval(500);
+
+ err_out = PR_STDERR;
+ std_out = PR_STDOUT;
+ accept_timeout = PR_SecondsToInterval(2);
+ emu_layer_ident = PR_GetUniqueIdentity("Emulated AcceptRead");
+ emu_layer_methods = *PR_GetDefaultIOMethods();
+ emu_layer_methods.acceptread = emu_AcceptRead;
+
+ if (argc != 2 && argc != 3) {
+ port_number = DEFAULT_PORT;
+ }
+ else {
+ port_number = (PRUint16)atoi(argv[(argc == 2) ? 1 : 2]);
+ }
+
+ status = PR_InitializeNetAddr(PR_IpAddrAny, port_number, &server_addr);
+ if (PR_SUCCESS != status)
+ {
+ PL_FPrintError(err_out, "PR_InitializeNetAddr failed");
+ PR_ProcessExit(1);
+ }
+ if (argc < 3)
+ {
+ status = PR_InitializeNetAddr(
+ PR_IpAddrLoopback, port_number, &client_addr);
+ if (PR_SUCCESS != status)
+ {
+ PL_FPrintError(err_out, "PR_InitializeNetAddr failed");
+ PR_ProcessExit(1);
+ }
+ }
+ else
+ {
+ status = PR_GetHostByName(
+ argv[1], netdb_buf, sizeof(netdb_buf), &he);
+ if (status == PR_FAILURE)
+ {
+ PL_FPrintError(err_out, "PR_GetHostByName failed");
+ PR_ProcessExit(1);
+ }
+ next_index = PR_EnumerateHostEnt(0, &he, port_number, &client_addr);
+ if (next_index == -1)
+ {
+ PL_FPrintError(err_out, "PR_EnumerateHostEnt failed");
+ PR_ProcessExit(1);
+ }
+ }
+
+ for (
+ write_dally = 0;
+ write_dally < accept_timeout + (2 * delta);
+ write_dally += delta)
+ {
+ PR_fprintf(
+ std_out, "Testing w/ write_dally = %d msec\n",
+ PR_IntervalToMilliseconds(write_dally));
+ server_thread = PR_CreateThread(
+ PR_USER_THREAD, AcceptingThread, &server_addr,
+ PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0);
+ if (server_thread == NULL)
+ {
+ PL_FPrintError(err_out, "PR_CreateThread (server) failed");
+ PR_ProcessExit(1);
+ }
+
+ PR_Sleep(delta); /* let the server pot thicken */
+
+ client_thread = PR_CreateThread(
+ PR_USER_THREAD, ConnectingThread, &client_addr,
+ PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0);
+ if (client_thread == NULL)
+ {
+ PL_FPrintError(err_out, "PR_CreateThread (client) failed");
+ PR_ProcessExit(1);
+ }
+
+ if (PR_JoinThread(client_thread) == PR_FAILURE) {
+ PL_FPrintError(err_out, "PR_JoinThread (client) failed");
+ }
+
+ if (PR_JoinThread(server_thread) == PR_FAILURE) {
+ PL_FPrintError(err_out, "PR_JoinThread (server) failed");
+ }
+ }
+
+ return 0;
+}
diff --git a/nsprpub/pr/tests/addrstr.c b/nsprpub/pr/tests/addrstr.c
new file mode 100644
index 0000000000..b6736a74bf
--- /dev/null
+++ b/nsprpub/pr/tests/addrstr.c
@@ -0,0 +1,82 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "prnetdb.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+const char *testaddrs[] = {
+ "::", "::",
+ "::1", "::1",
+ "::ffff", "::ffff",
+ "::1:0", "::0.1.0.0",
+ "::127.0.0.1", "::127.0.0.1",
+ "::FFFF:127.0.0.1", "::ffff:127.0.0.1",
+ "::FFFE:9504:3501", "::fffe:9504:3501",
+ "0:0:1:0:35c:0:0:0", "0:0:1:0:35c::",
+ "0:0:3f4c:0:0:4552:0:0", "::3f4c:0:0:4552:0:0",
+ "0:0:1245:0:0:0:0567:0", "0:0:1245::567:0",
+ "0:1:2:3:4:5:6:7", "0:1:2:3:4:5:6:7",
+ "1:2:3:0:4:5:6:7", "1:2:3:0:4:5:6:7",
+ "1:2:3:4:5:6:7:0", "1:2:3:4:5:6:7:0",
+ "1:2:3:4:5:6:7:8", "1:2:3:4:5:6:7:8",
+ "1:2:3:4:5:6::7", "1:2:3:4:5:6:0:7",
+ 0
+};
+
+const char *badaddrs[] = {
+ "::.1.2.3",
+ "ffff::.1.2.3",
+ "1:2:3:4:5:6:7::8",
+ "1:2:3:4:5:6::7:8",
+ "::ff99.2.3.4",
+ 0
+};
+
+int failed_already = 0;
+
+int main(int argc, char **argv)
+{
+ const char **nexttestaddr = testaddrs;
+ const char **nextbadaddr = badaddrs;
+ const char *in, *expected_out;
+ PRNetAddr addr;
+ char buf[256];
+ PRStatus rv;
+
+ while ((in = *nexttestaddr++) != 0) {
+ expected_out = *nexttestaddr++;
+ rv = PR_StringToNetAddr(in, &addr);
+ if (rv) {
+ printf("cannot convert %s to addr: %d\n", in, rv);
+ failed_already = 1;
+ continue;
+ }
+ rv = PR_NetAddrToString(&addr, buf, sizeof(buf));
+ if (rv) {
+ printf("cannot convert %s back to string: %d\n", in, rv);
+ failed_already = 1;
+ continue;
+ }
+ if (strcmp(buf, expected_out)) {
+ /* This is not necessarily an error */
+ printf("%s expected %s got %s\n", in, expected_out, buf);
+ }
+ }
+ while ((in = *nextbadaddr++) != 0) {
+ if (PR_StringToNetAddr(in, &addr) == PR_SUCCESS) {
+ printf("converted bad addr %s\n", in);
+ failed_already = 1;
+ }
+ }
+ if (failed_already) {
+ printf("FAIL\n");
+ return 1;
+ }
+ printf("PASS\n");
+ return 0;
+}
diff --git a/nsprpub/pr/tests/affinity.c b/nsprpub/pr/tests/affinity.c
new file mode 100644
index 0000000000..14d08efc11
--- /dev/null
+++ b/nsprpub/pr/tests/affinity.c
@@ -0,0 +1,84 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nspr.h"
+#include "pprthred.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/nsprpub/pr/tests/alarm.c b/nsprpub/pr/tests/alarm.c
new file mode 100644
index 0000000000..10a148e448
--- /dev/null
+++ b/nsprpub/pr/tests/alarm.c
@@ -0,0 +1,552 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/***********************************************************************
+** 1996 - Netscape Communications Corporation
+**
+** Name: alarmtst.c
+**
+** Description: Test alarms
+**
+** Modification History:
+** 13-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
+** The debug mode will print all of the printfs associated with this test.
+** The regress mode will be the default mode. Since the regress tool limits
+** the output to a one line status:PASS or FAIL,all of the printf statements
+** have been handled with an if (debug_mode) statement.
+** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to
+** recognize the return code from tha main program.
+***********************************************************************/
+
+/***********************************************************************
+** Includes
+***********************************************************************/
+
+#include "prlog.h"
+#include "prinit.h"
+#include "obsolete/pralarm.h"
+#include "prlock.h"
+#include "prlong.h"
+#include "prcvar.h"
+#include "prinrval.h"
+#include "prtime.h"
+
+/* Used to get the command line option */
+#include "plgetopt.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+#if defined(XP_UNIX)
+#include <sys/time.h>
+#endif
+
+static PRIntn debug_mode;
+static PRIntn failed_already=0;
+static PRThreadScope thread_scope = PR_LOCAL_THREAD;
+
+typedef struct notifyData {
+ PRLock *ml;
+ PRCondVar *child;
+ PRCondVar *parent;
+ PRBool pending;
+ PRUint32 counter;
+} NotifyData;
+
+static void Notifier(void *arg)
+{
+ NotifyData *notifyData = (NotifyData*)arg;
+ PR_Lock(notifyData->ml);
+ while (notifyData->counter > 0)
+ {
+ while (!notifyData->pending) {
+ PR_WaitCondVar(notifyData->child, PR_INTERVAL_NO_TIMEOUT);
+ }
+ notifyData->counter -= 1;
+ notifyData->pending = PR_FALSE;
+ PR_NotifyCondVar(notifyData->parent);
+ }
+ PR_Unlock(notifyData->ml);
+} /* Notifier */
+/***********************************************************************
+** PRIVATE FUNCTION: ConditionNotify
+** DESCRIPTION:
+**
+** INPUTS: loops
+** OUTPUTS: None
+** RETURN: overhead
+** SIDE EFFECTS:
+**
+** RESTRICTIONS:
+** None
+** MEMORY: NA
+** ALGORITHM:
+**
+***********************************************************************/
+
+
+static PRIntervalTime ConditionNotify(PRUint32 loops)
+{
+ PRThread *thread;
+ NotifyData notifyData;
+ PRIntervalTime timein, overhead;
+
+ timein = PR_IntervalNow();
+
+ notifyData.counter = loops;
+ notifyData.ml = PR_NewLock();
+ notifyData.child = PR_NewCondVar(notifyData.ml);
+ notifyData.parent = PR_NewCondVar(notifyData.ml);
+ thread = PR_CreateThread(
+ PR_USER_THREAD, Notifier, &notifyData,
+ PR_GetThreadPriority(PR_GetCurrentThread()),
+ thread_scope, PR_JOINABLE_THREAD, 0);
+
+ overhead = PR_IntervalNow() - timein; /* elapsed so far */
+
+ PR_Lock(notifyData.ml);
+ while (notifyData.counter > 0)
+ {
+ notifyData.pending = PR_TRUE;
+ PR_NotifyCondVar(notifyData.child);
+ while (notifyData.pending) {
+ PR_WaitCondVar(notifyData.parent, PR_INTERVAL_NO_TIMEOUT);
+ }
+ }
+ PR_Unlock(notifyData.ml);
+
+ timein = PR_IntervalNow();
+
+ (void)PR_JoinThread(thread);
+ PR_DestroyCondVar(notifyData.child);
+ PR_DestroyCondVar(notifyData.parent);
+ PR_DestroyLock(notifyData.ml);
+
+ overhead += (PR_IntervalNow() - timein); /* more overhead */
+
+ return overhead;
+} /* ConditionNotify */
+
+static PRIntervalTime ConditionTimeout(PRUint32 loops)
+{
+ PRUintn count;
+ PRIntervalTime overhead, timein = PR_IntervalNow();
+
+ PRLock *ml = PR_NewLock();
+ PRCondVar *cv = PR_NewCondVar(ml);
+ PRIntervalTime interval = PR_MillisecondsToInterval(50);
+
+ overhead = PR_IntervalNow() - timein;
+
+ PR_Lock(ml);
+ for (count = 0; count < loops; ++count)
+ {
+ overhead += interval;
+ PR_ASSERT(PR_WaitCondVar(cv, interval) == PR_SUCCESS);
+ }
+ PR_Unlock(ml);
+
+ timein = PR_IntervalNow();
+ PR_DestroyCondVar(cv);
+ PR_DestroyLock(ml);
+ overhead += (PR_IntervalNow() - timein);
+
+ return overhead;
+} /* ConditionTimeout */
+
+typedef struct AlarmData {
+ PRLock *ml;
+ PRCondVar *cv;
+ PRUint32 rate, late, times;
+ PRIntervalTime duration, timein, period;
+} AlarmData;
+
+static PRBool AlarmFn1(PRAlarmID *id, void *clientData, PRUint32 late)
+{
+ PRStatus rv = PR_SUCCESS;
+ PRBool keepGoing, resetAlarm;
+ PRIntervalTime interval, now = PR_IntervalNow();
+ AlarmData *ad = (AlarmData*)clientData;
+
+ PR_Lock(ad->ml);
+ ad->late += late;
+ ad->times += 1;
+ keepGoing = ((PRIntervalTime)(now - ad->timein) < ad->duration) ?
+ PR_TRUE : PR_FALSE;
+ if (!keepGoing) {
+ rv = PR_NotifyCondVar(ad->cv);
+ }
+ resetAlarm = ((ad->times % 31) == 0) ? PR_TRUE : PR_FALSE;
+
+ interval = (ad->period + ad->rate - 1) / ad->rate;
+ if (!late && (interval > 10))
+ {
+ interval &= (now & 0x03) + 1;
+ PR_WaitCondVar(ad->cv, interval);
+ }
+
+ PR_Unlock(ad->ml);
+
+ if (rv != PR_SUCCESS)
+ {
+ if (!debug_mode) {
+ failed_already=1;
+ }
+ else {
+ printf("AlarmFn: notify status: FAIL\n");
+ }
+
+ }
+
+ if (resetAlarm)
+ {
+ ad->rate += 3;
+ ad->late = ad->times = 0;
+ if (PR_ResetAlarm(id, ad->period, ad->rate) != PR_SUCCESS)
+ {
+ if (!debug_mode) {
+ failed_already=1;
+ }
+ else {
+ printf("AlarmFn: Resetting alarm status: FAIL\n");
+ }
+
+ keepGoing = PR_FALSE;
+ }
+
+ }
+
+ return keepGoing;
+} /* AlarmFn1 */
+
+static PRIntervalTime Alarms1(PRUint32 loops)
+{
+ PRAlarm *alarm;
+ AlarmData ad;
+ PRIntervalTime overhead, timein = PR_IntervalNow();
+ PRIntervalTime duration = PR_SecondsToInterval(3);
+
+ PRLock *ml = PR_NewLock();
+ PRCondVar *cv = PR_NewCondVar(ml);
+
+ ad.ml = ml;
+ ad.cv = cv;
+ ad.rate = 1;
+ ad.times = loops;
+ ad.late = ad.times = 0;
+ ad.duration = duration;
+ ad.timein = PR_IntervalNow();
+ ad.period = PR_SecondsToInterval(1);
+
+ alarm = PR_CreateAlarm();
+
+ (void)PR_SetAlarm(
+ alarm, ad.period, ad.rate, AlarmFn1, &ad);
+
+ overhead = PR_IntervalNow() - timein;
+
+ PR_Lock(ml);
+ while ((PRIntervalTime)(PR_IntervalNow() - ad.timein) < duration) {
+ PR_WaitCondVar(cv, PR_INTERVAL_NO_TIMEOUT);
+ }
+ PR_Unlock(ml);
+
+ timein = PR_IntervalNow();
+ (void)PR_DestroyAlarm(alarm);
+ PR_DestroyCondVar(cv);
+ PR_DestroyLock(ml);
+ overhead += (PR_IntervalNow() - timein);
+
+ return duration + overhead;
+} /* Alarms1 */
+
+static PRBool AlarmFn2(PRAlarmID *id, void *clientData, PRUint32 late)
+{
+ PRBool keepGoing;
+ PRStatus rv = PR_SUCCESS;
+ AlarmData *ad = (AlarmData*)clientData;
+ PRIntervalTime interval, now = PR_IntervalNow();
+
+ PR_Lock(ad->ml);
+ ad->times += 1;
+ keepGoing = ((PRIntervalTime)(now - ad->timein) < ad->duration) ?
+ PR_TRUE : PR_FALSE;
+ interval = (ad->period + ad->rate - 1) / ad->rate;
+
+ if (!late && (interval > 10))
+ {
+ interval &= (now & 0x03) + 1;
+ PR_WaitCondVar(ad->cv, interval);
+ }
+
+ if (!keepGoing) {
+ rv = PR_NotifyCondVar(ad->cv);
+ }
+
+ PR_Unlock(ad->ml);
+
+
+ if (rv != PR_SUCCESS) {
+ failed_already=1;
+ };
+
+ return keepGoing;
+} /* AlarmFn2 */
+
+static PRIntervalTime Alarms2(PRUint32 loops)
+{
+ PRStatus rv;
+ PRAlarm *alarm;
+ PRIntervalTime overhead, timein = PR_IntervalNow();
+ AlarmData ad;
+ PRIntervalTime duration = PR_SecondsToInterval(30);
+
+ PRLock *ml = PR_NewLock();
+ PRCondVar *cv = PR_NewCondVar(ml);
+
+ ad.ml = ml;
+ ad.cv = cv;
+ ad.rate = 1;
+ ad.times = loops;
+ ad.late = ad.times = 0;
+ ad.duration = duration;
+ ad.timein = PR_IntervalNow();
+ ad.period = PR_SecondsToInterval(1);
+
+ alarm = PR_CreateAlarm();
+
+ (void)PR_SetAlarm(
+ alarm, ad.period, ad.rate, AlarmFn2, &ad);
+
+ overhead = PR_IntervalNow() - timein;
+
+ PR_Lock(ml);
+ while ((PRIntervalTime)(PR_IntervalNow() - ad.timein) < duration) {
+ PR_WaitCondVar(cv, PR_INTERVAL_NO_TIMEOUT);
+ }
+ PR_Unlock(ml);
+
+ timein = PR_IntervalNow();
+
+ rv = PR_DestroyAlarm(alarm);
+ if (rv != PR_SUCCESS)
+ {
+ if (!debug_mode) {
+ failed_already=1;
+ }
+ else {
+ printf("***Destroying alarm status: FAIL\n");
+ }
+ }
+
+
+ PR_DestroyCondVar(cv);
+ PR_DestroyLock(ml);
+
+ overhead += (PR_IntervalNow() - timein);
+
+ return duration + overhead;
+} /* Alarms2 */
+
+static PRIntervalTime Alarms3(PRUint32 loops)
+{
+ PRIntn i;
+ PRStatus rv;
+ PRAlarm *alarm;
+ AlarmData ad[3];
+ PRIntervalTime duration = PR_SecondsToInterval(30);
+ PRIntervalTime overhead, timein = PR_IntervalNow();
+
+ PRLock *ml = PR_NewLock();
+ PRCondVar *cv = PR_NewCondVar(ml);
+
+ for (i = 0; i < 3; ++i)
+ {
+ ad[i].ml = ml;
+ ad[i].cv = cv;
+ ad[i].rate = 1;
+ ad[i].times = loops;
+ ad[i].duration = duration;
+ ad[i].late = ad[i].times = 0;
+ ad[i].timein = PR_IntervalNow();
+ ad[i].period = PR_SecondsToInterval(1);
+
+ /* more loops, faster rate => same elapsed time */
+ ad[i].times = (i + 1) * loops;
+ ad[i].rate = (i + 1) * 10;
+ }
+
+ alarm = PR_CreateAlarm();
+
+ for (i = 0; i < 3; ++i)
+ {
+ (void)PR_SetAlarm(
+ alarm, ad[i].period, ad[i].rate,
+ AlarmFn2, &ad[i]);
+ }
+
+ overhead = PR_IntervalNow() - timein;
+
+ PR_Lock(ml);
+ for (i = 0; i < 3; ++i)
+ {
+ while ((PRIntervalTime)(PR_IntervalNow() - ad[i].timein) < duration) {
+ PR_WaitCondVar(cv, PR_INTERVAL_NO_TIMEOUT);
+ }
+ }
+ PR_Unlock(ml);
+
+ timein = PR_IntervalNow();
+
+ if (debug_mode)
+ printf
+ ("Alarms3 finished at %u, %u, %u\n",
+ ad[0].timein, ad[1].timein, ad[2].timein);
+
+ rv = PR_DestroyAlarm(alarm);
+ if (rv != PR_SUCCESS)
+ {
+ if (!debug_mode) {
+ failed_already=1;
+ }
+ else {
+ printf("***Destroying alarm status: FAIL\n");
+ }
+ }
+ PR_DestroyCondVar(cv);
+ PR_DestroyLock(ml);
+
+ overhead += (duration / 3);
+ overhead += (PR_IntervalNow() - timein);
+
+ return overhead;
+} /* Alarms3 */
+
+static PRUint32 TimeThis(
+ const char *msg, PRUint32 (*func)(PRUint32 loops), PRUint32 loops)
+{
+ PRUint32 overhead, usecs;
+ PRIntervalTime predicted, timein, timeout, ticks;
+
+ if (debug_mode) {
+ printf("Testing %s ...", msg);
+ }
+
+ timein = PR_IntervalNow();
+ predicted = func(loops);
+ timeout = PR_IntervalNow();
+
+ if (debug_mode) {
+ printf(" done\n");
+ }
+
+ ticks = timeout - timein;
+ usecs = PR_IntervalToMicroseconds(ticks);
+ overhead = PR_IntervalToMicroseconds(predicted);
+
+ if(ticks < predicted)
+ {
+ if (debug_mode) {
+ printf("\tFinished in negative time\n");
+ printf("\tpredicted overhead was %d usecs\n", overhead);
+ printf("\ttest completed in %d usecs\n\n", usecs);
+ }
+ }
+ else
+ {
+ if (debug_mode)
+ printf(
+ "\ttotal: %d usecs\n\toverhead: %d usecs\n\tcost: %6.3f usecs\n\n",
+ usecs, overhead, ((double)(usecs - overhead) / (double)loops));
+ }
+
+ return overhead;
+} /* TimeThis */
+
+int prmain(int argc, char** argv)
+{
+ PRUint32 cpu, cpus = 0, loops = 0;
+
+ /* The command line argument: -d is used to determine if the test is being run
+ in debug mode. The regress tool requires only one line output:PASS or FAIL.
+ All of the printfs associated with this test has been handled with a if (debug_mode)
+ test.
+ Usage: test_name [-d]
+ */
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "Gdl:c:");
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 'G': /* GLOBAL threads */
+ thread_scope = PR_GLOBAL_THREAD;
+ break;
+ case 'd': /* debug mode */
+ debug_mode = 1;
+ break;
+ case 'l': /* loop count */
+ loops = atoi(opt->value);
+ break;
+ case 'c': /* concurrency limit */
+ cpus = atoi(opt->value);
+ break;
+ default:
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+
+ if (cpus == 0) {
+ cpus = 1;
+ }
+ if (loops == 0) {
+ loops = 4;
+ }
+
+ if (debug_mode) {
+ printf("Alarm: Using %d loops\n", loops);
+ }
+
+ if (debug_mode) {
+ printf("Alarm: Using %d cpu(s)\n", cpus);
+ }
+
+ for (cpu = 1; cpu <= cpus; ++cpu)
+ {
+ if (debug_mode) {
+ printf("\nAlarm: Using %d CPU(s)\n", cpu);
+ }
+
+ PR_SetConcurrency(cpu);
+
+ /* some basic time test */
+ (void)TimeThis("ConditionNotify", ConditionNotify, loops);
+ (void)TimeThis("ConditionTimeout", ConditionTimeout, loops);
+ (void)TimeThis("Alarms1", Alarms1, loops);
+ (void)TimeThis("Alarms2", Alarms2, loops);
+ (void)TimeThis("Alarms3", Alarms3, loops);
+ }
+ return 0;
+}
+
+int main(int argc, char** argv)
+{
+ PR_Initialize(prmain, argc, argv, 0);
+ PR_STDIO_INIT();
+ if (failed_already) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+
+} /* main */
+
+
+/* alarmtst.c */
diff --git a/nsprpub/pr/tests/anonfm.c b/nsprpub/pr/tests/anonfm.c
new file mode 100644
index 0000000000..529be6fae0
--- /dev/null
+++ b/nsprpub/pr/tests/anonfm.c
@@ -0,0 +1,319 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+** 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, LL_ZERO, 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, LL_ZERO, 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() */
+
+
+int main(int 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/nsprpub/pr/tests/append.c b/nsprpub/pr/tests/append.c
new file mode 100644
index 0000000000..64fe3ff2c1
--- /dev/null
+++ b/nsprpub/pr/tests/append.c
@@ -0,0 +1,146 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+** File: append.c
+** Description: Testing File writes where PR_APPEND was used on open
+**
+** append attempts to verify that a file opened with PR_APPEND
+** will always append to the end of file, regardless where the
+** current file pointer is positioned. To do this, PR_Seek() is
+** called before each write with the position set to beginning of
+** file. Subsequent writes should always append.
+** The file is read back, summing the integer data written to the
+** file. If the expected result is equal, the test passes.
+**
+** See BugSplat: 4090
+*/
+#include "plgetopt.h"
+#include "nspr.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+PRIntn debug = 0;
+PRIntn verbose = 0;
+PRBool failedAlready = PR_FALSE;
+const PRInt32 addedBytes = 1000;
+const PRInt32 buf = 1; /* constant written to fd, addedBytes times */
+PRInt32 inBuf; /* read it back into here */
+
+int main(int argc, char **argv)
+{
+ PRStatus rc;
+ PRInt32 rv;
+ PRFileDesc *fd;
+ PRIntn i;
+ PRInt32 sum = 0;
+
+ { /* Get command line options */
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "vd");
+
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 'd': /* debug */
+ debug = 1;
+ break;
+ case 'v': /* verbose */
+ verbose = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+ } /* end block "Get command line options" */
+ /* ---------------------------------------------------------------------- */
+ fd = PR_Open( "./tmp-nsprAppend", (PR_APPEND | PR_CREATE_FILE | PR_TRUNCATE | PR_WRONLY), 0666 );
+ if ( NULL == fd ) {
+ if (debug) {
+ printf("PR_Open() failed for writing: %d\n", PR_GetError());
+ }
+ failedAlready = PR_TRUE;
+ goto Finished;
+ }
+
+ for ( i = 0; i < addedBytes ; i++ ) {
+ rv = PR_Write( fd, &buf, sizeof(buf));
+ if ( sizeof(buf) != rv ) {
+ if (debug) {
+ printf("PR_Write() failed: %d\n", PR_GetError());
+ }
+ failedAlready = PR_TRUE;
+ goto Finished;
+ }
+ rv = PR_Seek( fd, 0, PR_SEEK_SET );
+ if ( -1 == rv ) {
+ if (debug) {
+ printf("PR_Seek() failed: %d\n", PR_GetError());
+ }
+ failedAlready = PR_TRUE;
+ goto Finished;
+ }
+ }
+ rc = PR_Close( fd );
+ if ( PR_FAILURE == rc ) {
+ if (debug) {
+ printf("PR_Close() failed after writing: %d\n", PR_GetError());
+ }
+ failedAlready = PR_TRUE;
+ goto Finished;
+ }
+ /* ---------------------------------------------------------------------- */
+ fd = PR_Open( "./tmp-nsprAppend", PR_RDONLY, 0 );
+ if ( NULL == fd ) {
+ if (debug) {
+ printf("PR_Open() failed for reading: %d\n", PR_GetError());
+ }
+ failedAlready = PR_TRUE;
+ goto Finished;
+ }
+
+ for ( i = 0; i < addedBytes ; i++ ) {
+ rv = PR_Read( fd, &inBuf, sizeof(inBuf));
+ if ( sizeof(inBuf) != rv) {
+ if (debug) {
+ printf("PR_Write() failed: %d\n", PR_GetError());
+ }
+ failedAlready = PR_TRUE;
+ goto Finished;
+ }
+ sum += inBuf;
+ }
+
+ rc = PR_Close( fd );
+ if ( PR_FAILURE == rc ) {
+ if (debug) {
+ printf("PR_Close() failed after reading: %d\n", PR_GetError());
+ }
+ failedAlready = PR_TRUE;
+ goto Finished;
+ }
+ if ( sum != addedBytes ) {
+ if (debug) {
+ printf("Uh Oh! addedBytes: %d. Sum: %d\n", addedBytes, sum);
+ }
+ failedAlready = PR_TRUE;
+ goto Finished;
+ }
+
+ /* ---------------------------------------------------------------------- */
+Finished:
+ if (debug || verbose) {
+ printf("%s\n", (failedAlready)? "FAILED" : "PASSED" );
+ }
+ return( (failedAlready)? 1 : 0 );
+} /* main() */
+
+/* append.c */
diff --git a/nsprpub/pr/tests/atomic.c b/nsprpub/pr/tests/atomic.c
new file mode 100644
index 0000000000..42d25da8df
--- /dev/null
+++ b/nsprpub/pr/tests/atomic.c
@@ -0,0 +1,183 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "prio.h"
+#include "prprf.h"
+#include "pratom.h"
+
+/*
+ * TODO: create a macro to generate the six lines of code that are repeated
+ * for every test. Also rewrite the statement
+ * result = result | ((EXPRESSION) ? 0 : 1);
+ * as
+ * result |= !(EXPRESSION);
+ */
+
+int main(int argc, char **argv)
+{
+ PRInt32 rv, oldval, test, result = 0;
+ PRFileDesc *output = PR_GetSpecialFD(PR_StandardOutput);
+
+ /***********************/
+ /* Test the functions. */
+ /***********************/
+
+ oldval = test = -2;
+ rv = PR_AtomicIncrement(&test);
+ result = result | ((rv == -1) ? 0 : 1);
+ PR_fprintf(
+ output, "PR_AtomicIncrement(%d) == %d: %s\n",
+ oldval, rv, (rv == -1) ? "PASSED" : "FAILED");
+ oldval = test;
+ rv = PR_AtomicIncrement(&test);
+ result = result | ((rv == 0) ? 0 : 1);
+ PR_fprintf(
+ output, "PR_AtomicIncrement(%d) == %d: %s\n",
+ oldval, rv, (rv == 0) ? "PASSED" : "FAILED");
+ oldval = test;
+ rv = PR_AtomicIncrement(&test);
+ result = result | ((rv == 1) ? 0 : 1);
+ PR_fprintf(
+ output, "PR_AtomicIncrement(%d) == %d: %s\n",
+ oldval, rv, (rv == 1) ? "PASSED" : "FAILED");
+
+ oldval = test = -2;
+ rv = PR_AtomicAdd(&test,1);
+ result = result | ((rv == -1) ? 0 : 1);
+ PR_fprintf(
+ output, "PR_AtomicAdd(%d,%d) == %d: %s\n",
+ oldval, 1, rv, (rv == -1) ? "PASSED" : "FAILED");
+ oldval = test;
+ rv = PR_AtomicAdd(&test, 4);
+ result = result | ((rv == 3) ? 0 : 1);
+ PR_fprintf(
+ output, "PR_AtomicAdd(%d,%d) == %d: %s\n",
+ oldval, 4, rv, (rv == 3) ? "PASSED" : "FAILED");
+ oldval = test;
+ rv = PR_AtomicAdd(&test, -6);
+ result = result | ((rv == -3) ? 0 : 1);
+ PR_fprintf(
+ output, "PR_AtomicAdd(%d,%d) == %d: %s\n",
+ oldval, -6, rv, (rv == -3) ? "PASSED" : "FAILED");
+
+ oldval = test = 2;
+ rv = PR_AtomicDecrement(&test);
+ result = result | ((rv == 1) ? 0 : 1);
+ PR_fprintf(
+ output, "PR_AtomicDecrement(%d) == %d: %s\n",
+ oldval, rv, (rv == 1) ? "PASSED" : "FAILED");
+ oldval = test;
+ rv = PR_AtomicDecrement(&test);
+ result = result | ((rv == 0) ? 0 : 1);
+ PR_fprintf(
+ output, "PR_AtomicDecrement(%d) == %d: %s\n",
+ oldval, rv, (rv == 0) ? "PASSED" : "FAILED");
+ oldval = test;
+ rv = PR_AtomicDecrement(&test);
+ result = result | ((rv == -1) ? 0 : 1);
+ PR_fprintf(
+ output, "PR_AtomicDecrement(%d) == %d: %s\n",
+ oldval, rv, (rv == -1) ? "PASSED" : "FAILED");
+
+ /* set to a different value */
+ oldval = test = -2;
+ rv = PR_AtomicSet(&test, 2);
+ result = result | (((rv == -2) && (test == 2)) ? 0 : 1);
+ PR_fprintf(
+ output, "PR_AtomicSet(%d, %d) == %d: %s\n",
+ oldval, 2, rv, ((rv == -2) && (test == 2)) ? "PASSED" : "FAILED");
+
+ /* set to the same value */
+ oldval = test = -2;
+ rv = PR_AtomicSet(&test, -2);
+ result = result | (((rv == -2) && (test == -2)) ? 0 : 1);
+ PR_fprintf(
+ output, "PR_AtomicSet(%d, %d) == %d: %s\n",
+ oldval, -2, rv, ((rv == -2) && (test == -2)) ? "PASSED" : "FAILED");
+
+ /***********************/
+ /* Test the macros. */
+ /***********************/
+
+ oldval = test = -2;
+ rv = PR_ATOMIC_INCREMENT(&test);
+ result = result | ((rv == -1) ? 0 : 1);
+ PR_fprintf(
+ output, "PR_ATOMIC_INCREMENT(%d) == %d: %s\n",
+ oldval, rv, (rv == -1) ? "PASSED" : "FAILED");
+ oldval = test;
+ rv = PR_ATOMIC_INCREMENT(&test);
+ result = result | ((rv == 0) ? 0 : 1);
+ PR_fprintf(
+ output, "PR_ATOMIC_INCREMENT(%d) == %d: %s\n",
+ oldval, rv, (rv == 0) ? "PASSED" : "FAILED");
+ oldval = test;
+ rv = PR_ATOMIC_INCREMENT(&test);
+ result = result | ((rv == 1) ? 0 : 1);
+ PR_fprintf(
+ output, "PR_ATOMIC_INCREMENT(%d) == %d: %s\n",
+ oldval, rv, (rv == 1) ? "PASSED" : "FAILED");
+
+ oldval = test = -2;
+ rv = PR_ATOMIC_ADD(&test,1);
+ result = result | ((rv == -1) ? 0 : 1);
+ PR_fprintf(
+ output, "PR_ATOMIC_ADD(%d,%d) == %d: %s\n",
+ oldval, 1, rv, (rv == -1) ? "PASSED" : "FAILED");
+ oldval = test;
+ rv = PR_ATOMIC_ADD(&test, 4);
+ result = result | ((rv == 3) ? 0 : 1);
+ PR_fprintf(
+ output, "PR_ATOMIC_ADD(%d,%d) == %d: %s\n",
+ oldval, 4, rv, (rv == 3) ? "PASSED" : "FAILED");
+ oldval = test;
+ rv = PR_ATOMIC_ADD(&test, -6);
+ result = result | ((rv == -3) ? 0 : 1);
+ PR_fprintf(
+ output, "PR_ATOMIC_ADD(%d,%d) == %d: %s\n",
+ oldval, -6, rv, (rv == -3) ? "PASSED" : "FAILED");
+
+ oldval = test = 2;
+ rv = PR_ATOMIC_DECREMENT(&test);
+ result = result | ((rv == 1) ? 0 : 1);
+ PR_fprintf(
+ output, "PR_ATOMIC_DECREMENT(%d) == %d: %s\n",
+ oldval, rv, (rv == 1) ? "PASSED" : "FAILED");
+ oldval = test;
+ rv = PR_ATOMIC_DECREMENT(&test);
+ result = result | ((rv == 0) ? 0 : 1);
+ PR_fprintf(
+ output, "PR_ATOMIC_DECREMENT(%d) == %d: %s\n",
+ oldval, rv, (rv == 0) ? "PASSED" : "FAILED");
+ oldval = test;
+ rv = PR_ATOMIC_DECREMENT(&test);
+ result = result | ((rv == -1) ? 0 : 1);
+ PR_fprintf(
+ output, "PR_ATOMIC_DECREMENT(%d) == %d: %s\n",
+ oldval, rv, (rv == -1) ? "PASSED" : "FAILED");
+
+ /* set to a different value */
+ oldval = test = -2;
+ rv = PR_ATOMIC_SET(&test, 2);
+ result = result | (((rv == -2) && (test == 2)) ? 0 : 1);
+ PR_fprintf(
+ output, "PR_ATOMIC_SET(%d, %d) == %d: %s\n",
+ oldval, 2, rv, ((rv == -2) && (test == 2)) ? "PASSED" : "FAILED");
+
+ /* set to the same value */
+ oldval = test = -2;
+ rv = PR_ATOMIC_SET(&test, -2);
+ result = result | (((rv == -2) && (test == -2)) ? 0 : 1);
+ PR_fprintf(
+ output, "PR_ATOMIC_SET(%d, %d) == %d: %s\n",
+ oldval, -2, rv, ((rv == -2) && (test == -2)) ? "PASSED" : "FAILED");
+
+ PR_fprintf(
+ output, "Atomic operations test %s\n",
+ (result == 0) ? "PASSED" : "FAILED");
+ return result;
+} /* main */
+
+/* atomic.c */
diff --git a/nsprpub/pr/tests/attach.c b/nsprpub/pr/tests/attach.c
new file mode 100644
index 0000000000..2c1ac99799
--- /dev/null
+++ b/nsprpub/pr/tests/attach.c
@@ -0,0 +1,299 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/***********************************************************************
+** 1996 - Netscape Communications Corporation
+**
+** Name: attach.c
+**
+** Description: Platform-specific code to create a native thread. The native thread will
+** repeatedly call PR_AttachThread and PR_DetachThread. The
+** primordial thread waits for this new thread to finish.
+**
+** Modification History:
+** 13-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
+** The debug mode will print all of the printfs associated with this test.
+** The regress mode will be the default mode. Since the regress tool limits
+** the output to a one line status:PASS or FAIL,all of the printf statements
+** have been handled with an if (debug_mode) statement.
+** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to
+** recognize the return code from tha main program.
+** 12-June-97 Revert to return code 0 and 1.
+***********************************************************************/
+
+/***********************************************************************
+** Includes
+***********************************************************************/
+
+/* Used to get the command line option */
+#include "nspr.h"
+#include "pprthred.h"
+#include "plgetopt.h"
+
+#include <stdio.h>
+
+#ifdef WIN32
+#include <windows.h>
+#include <process.h>
+#elif defined(_PR_PTHREADS)
+#include <pthread.h>
+#include "md/_pth.h"
+#elif defined(SOLARIS)
+#include <thread.h>
+#elif defined(OS2)
+#define INCL_DOS
+#define INCL_ERRORS
+#include <os2.h>
+#include <process.h>
+#endif
+
+#define DEFAULT_COUNT 1000
+PRIntn failed_already=0;
+PRIntn debug_mode;
+
+
+int count;
+
+
+static void
+AttachDetach(void)
+{
+ PRThread *me;
+ PRInt32 index;
+
+ for (index=0; index<count; index++) {
+ me = PR_AttachThread(PR_USER_THREAD,
+ PR_PRIORITY_NORMAL,
+ NULL);
+
+ if (!me) {
+ fprintf(stderr, "Error attaching thread %d: PR_AttachThread failed\n",
+ count);
+ failed_already = 1;
+ return;
+ }
+ PR_DetachThread();
+ }
+}
+
+/************************************************************************/
+
+static void Measure(void (*func)(void), const char *msg)
+{
+ PRIntervalTime start, stop;
+ double d;
+
+ start = PR_IntervalNow();
+ (*func)();
+ stop = PR_IntervalNow();
+
+ d = (double)PR_IntervalToMicroseconds(stop - start);
+ if (debug_mode) {
+ printf("%40s: %6.2f usec\n", msg, d / count);
+ }
+}
+
+#ifdef WIN32
+static unsigned __stdcall threadStartFunc(void *arg)
+#else
+static void * threadStartFunc(void *arg)
+#endif
+{
+ Measure(AttachDetach, "Attach/Detach");
+
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+#ifdef _PR_PTHREADS
+ int rv;
+ pthread_t threadID;
+ pthread_attr_t attr;
+#elif defined(SOLARIS)
+ int rv;
+ thread_t threadID;
+#elif defined(WIN32)
+ DWORD rv;
+ unsigned threadID;
+ HANDLE hThread;
+#elif defined(OS2)
+ int rv;
+ TID threadID;
+#endif
+
+ /* The command line argument: -d is used to determine if the test is being run
+ in debug mode. The regress tool requires only one line output:PASS or FAIL.
+ All of the printfs associated with this test has been handled with a if (debug_mode)
+ test.
+ Usage: test_name [-d] [-c n]
+ */
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "dc:");
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 'd': /* debug mode */
+ debug_mode = 1;
+ break;
+ case 'c': /* loop count */
+ count = atoi(opt->value);
+ break;
+ default:
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+#if defined(WIN16)
+ printf("attach: This test is not valid for Win16\n");
+ goto exit_now;
+#endif
+
+ if(0 == count) {
+ count = DEFAULT_COUNT;
+ }
+
+ /*
+ * To force the implicit initialization of nspr20
+ */
+ PR_SetError(0, 0);
+ PR_STDIO_INIT();
+
+ /*
+ * Platform-specific code to create a native thread. The native
+ * thread will repeatedly call PR_AttachThread and PR_DetachThread.
+ * The primordial thread waits for this new thread to finish.
+ */
+
+#ifdef _PR_PTHREADS
+
+ rv = _PT_PTHREAD_ATTR_INIT(&attr);
+ if (debug_mode) {
+ PR_ASSERT(0 == rv);
+ }
+ else if (0 != rv) {
+ failed_already=1;
+ goto exit_now;
+ }
+
+ rv = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+ if (debug_mode) {
+ PR_ASSERT(0 == rv);
+ }
+ else if (0 != rv) {
+ failed_already=1;
+ goto exit_now;
+ }
+ rv = _PT_PTHREAD_CREATE(&threadID, attr, threadStartFunc, NULL);
+ if (rv != 0) {
+ fprintf(stderr, "thread creation failed: error code %d\n", rv);
+ failed_already=1;
+ goto exit_now;
+ }
+ else {
+ if (debug_mode) {
+ printf ("thread creation succeeded \n");
+ }
+
+ }
+ rv = _PT_PTHREAD_ATTR_DESTROY(&attr);
+ if (debug_mode) {
+ PR_ASSERT(0 == rv);
+ }
+ else if (0 != rv) {
+ failed_already=1;
+ goto exit_now;
+ }
+ rv = pthread_join(threadID, NULL);
+ if (debug_mode) {
+ PR_ASSERT(0 == rv);
+ }
+ else if (0 != rv) {
+ failed_already=1;
+ goto exit_now;
+ }
+
+#elif defined(SOLARIS)
+
+ rv = thr_create(NULL, 0, threadStartFunc, NULL, 0, &threadID);
+ if (rv != 0) {
+ if(!debug_mode) {
+ failed_already=1;
+ goto exit_now;
+ } else {
+ fprintf(stderr, "thread creation failed: error code %d\n", rv);
+ }
+ }
+ rv = thr_join(threadID, NULL, NULL);
+ if (debug_mode) {
+ PR_ASSERT(0 == rv);
+ }
+ else if (0 != rv)
+ {
+ failed_already=1;
+ goto exit_now;
+ }
+
+
+#elif defined(WIN32)
+
+ hThread = (HANDLE) _beginthreadex(NULL, 0, threadStartFunc, NULL,
+ STACK_SIZE_PARAM_IS_A_RESERVATION, &threadID);
+ if (hThread == 0) {
+ fprintf(stderr, "thread creation failed: error code %d\n",
+ GetLastError());
+ failed_already=1;
+ goto exit_now;
+ }
+ rv = WaitForSingleObject(hThread, INFINITE);
+ if (debug_mode) {
+ PR_ASSERT(rv != WAIT_FAILED);
+ }
+ else if (rv == WAIT_FAILED) {
+ failed_already=1;
+ goto exit_now;
+ }
+
+#elif defined(OS2)
+
+ threadID = (TID) _beginthread((void *)threadStartFunc, NULL,
+ 32768, NULL);
+ if (threadID == -1) {
+ fprintf(stderr, "thread creation failed: error code %d\n", errno);
+ failed_already=1;
+ goto exit_now;
+ }
+ rv = DosWaitThread(&threadID, DCWW_WAIT);
+ if (debug_mode) {
+ PR_ASSERT(rv == NO_ERROR);
+ } else if (rv != NO_ERROR) {
+ failed_already=1;
+ goto exit_now;
+ }
+
+#else
+ if (!debug_mode) {
+ failed_already=1;
+ }
+ else
+ printf("The attach test does not apply to this platform because\n"
+ "either this platform does not have native threads or the\n"
+ "test needs to be written for this platform.\n");
+ goto exit_now;
+#endif
+
+exit_now:
+ if(failed_already) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+}
diff --git a/nsprpub/pr/tests/bigfile.c b/nsprpub/pr/tests/bigfile.c
new file mode 100644
index 0000000000..e17a767e69
--- /dev/null
+++ b/nsprpub/pr/tests/bigfile.c
@@ -0,0 +1,358 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "prio.h"
+#include "prmem.h"
+#include "prprf.h"
+#include "prinit.h"
+#include "prerror.h"
+#include "prthread.h"
+
+#include "plerror.h"
+#include "plgetopt.h"
+
+#define DEFAULT_COUNT 10
+#define DEFAULT_FILESIZE 1
+#define BUFFER_SIZE 1000000
+
+typedef enum {v_silent, v_whisper, v_shout} Verbosity;
+static void Verbose(Verbosity, const char*, const char*, PRIntn);
+
+#define VERBOSE(_l, _m) Verbose(_l, _m, __FILE__, __LINE__)
+
+static PRIntn test_result = 2;
+static PRFileDesc *output = NULL;
+static PRIntn verbose = v_silent;
+static PRIntn filesize = DEFAULT_FILESIZE;
+
+static PRIntn Usage(void)
+{
+ PR_fprintf(output, "Bigfile test usage:\n");
+ PR_fprintf(output, ">bigfile [-G] [-d] [-v[*v]] [-s <n>] <filename>\n");
+ PR_fprintf(output, "\td\tdebug mode (equivalent to -vvv)\t(false)\n");
+ PR_fprintf(output, "\tv\tAdditional levels of output\t(none)\n");
+ PR_fprintf(output, "\tk\tKeep data file after exit\t(false)\n");
+ PR_fprintf(output, "\ts <n>\tFile size in megabytes\t\t(1 megabyte)\n");
+ PR_fprintf(output, "\t<filename>\tName of test file\t(none)\n");
+ return 2; /* nothing happened */
+} /* Usage */
+
+static PRStatus DeleteIfFound(const char *filename)
+{
+ PRStatus rv;
+ VERBOSE(v_shout, "Checking for existing file");
+ rv = PR_Access(filename, PR_ACCESS_WRITE_OK);
+ if (PR_SUCCESS == rv)
+ {
+ VERBOSE(v_shout, "Deleting existing file");
+ rv = PR_Delete(filename);
+ if (PR_FAILURE == rv) {
+ VERBOSE(v_shout, "Cannot delete big file");
+ }
+ }
+ else if (PR_FILE_NOT_FOUND_ERROR != PR_GetError()) {
+ VERBOSE(v_shout, "Cannot access big file");
+ }
+ else {
+ rv = PR_SUCCESS;
+ }
+ return rv;
+} /* DeleteIfFound */
+
+static PRIntn Error(const char *msg, const char *filename)
+{
+ PRInt32 error = PR_GetError();
+ if (NULL != msg)
+ {
+ if (0 == error) {
+ PR_fprintf(output, msg);
+ }
+ else {
+ PL_FPrintError(output, msg);
+ }
+ }
+ (void)DeleteIfFound(filename);
+ if (v_shout == verbose) {
+ PR_Abort();
+ }
+ return 1;
+} /* Error */
+
+static void Verbose(
+ Verbosity level, const char *msg, const char *file, PRIntn line)
+{
+ if (level <= verbose) {
+ PR_fprintf(output, "[%s : %d]: %s\n", file, line, msg);
+ }
+} /* Verbose */
+
+static void PrintInfo(PRFileInfo64 *info, const char *filename)
+{
+ PRExplodedTime tm;
+ char ctime[40], mtime[40];
+ static const char *types[] = {"FILE", "DIRECTORY", "OTHER"};
+ PR_fprintf(
+ output, "[%s : %d]: File info for %s\n",
+ __FILE__, __LINE__, filename);
+ PR_fprintf(
+ output, " type: %s, size: %llu bytes,\n",
+ types[info->type - 1], info->size);
+
+ PR_ExplodeTime(info->creationTime, PR_GMTParameters, &tm);
+ (void)PR_FormatTime(ctime, sizeof(ctime), "%c GMT", &tm);
+ PR_ExplodeTime(info->modifyTime, PR_GMTParameters, &tm);
+ (void)PR_FormatTime(mtime, sizeof(mtime), "%c GMT", &tm);
+
+ PR_fprintf(
+ output, " creation: %s,\n modify: %s\n", ctime, mtime);
+} /* PrintInfo */
+
+int main(int argc, char **argv)
+{
+ PRStatus rv;
+ char *buffer;
+ PLOptStatus os;
+ PRInt32 loop, bytes;
+ PRFileInfo small_info;
+ PRFileInfo64 big_info;
+ PRBool keep = PR_FALSE;
+ PRFileDesc *file = NULL;
+ const char *filename = NULL;
+ PRIntn count = DEFAULT_COUNT;
+ PRInt64 filesize64, big_answer, big_size, one_meg, zero_meg, big_fragment;
+ PRInt64 sevenFox = LL_INIT(0,0x7fffffff);
+
+ PLOptState *opt = PL_CreateOptState(argc, argv, "dtvhs:");
+
+ output = PR_GetSpecialFD(PR_StandardError);
+ PR_STDIO_INIT();
+
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 0:
+ filename = opt->value;
+ break;
+ case 'd': /* debug mode */
+ verbose = v_shout;
+ break;
+ case 'k': /* keep file */
+ keep = PR_TRUE;
+ break;
+ case 'v': /* verbosity */
+ if (v_shout > verbose) {
+ verbose += 1;
+ }
+ break;
+ case 'c': /* loop counter */
+ count = atoi(opt->value);
+ break;
+ case 's': /* filesize */
+ filesize = atoi(opt->value);
+ break;
+ case 'h': /* confused */
+ default:
+ return Usage();
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ if (0 == count) {
+ count = DEFAULT_COUNT;
+ }
+ if (0 == filesize) {
+ filesize = DEFAULT_FILESIZE;
+ }
+ if (NULL == filename)
+ {
+#define FILE_NAME "bigfile.dat"
+ if (DEFAULT_FILESIZE != filesize) {
+ return Usage();
+ }
+ else {
+ filename = FILE_NAME;
+ }
+ }
+
+ if (PR_FAILURE == DeleteIfFound(filename)) {
+ return 1;
+ }
+
+ test_result = 0;
+
+ LL_I2L(zero_meg, 0);
+ LL_I2L(one_meg, 1000000);
+ LL_I2L(filesize64, filesize);
+ buffer = (char*)PR_MALLOC(BUFFER_SIZE);
+ LL_I2L(big_fragment, BUFFER_SIZE);
+ LL_MUL(filesize64, filesize64, one_meg);
+
+ for (loop = 0; loop < BUFFER_SIZE; ++loop) {
+ buffer[loop] = (char)loop;
+ }
+
+ VERBOSE(v_whisper, "Creating big file");
+ file = PR_Open(filename, PR_CREATE_FILE | PR_WRONLY, 0666);
+ if (NULL == file) {
+ return Error("PR_Open()", filename);
+ }
+
+ VERBOSE(v_whisper, "Testing available space in empty file");
+ big_answer = file->methods->available64(file);
+ if (!LL_IS_ZERO(big_answer)) {
+ return Error("empty available64()", filename);
+ }
+
+ LL_SUB(big_size, filesize64, one_meg);
+ VERBOSE(v_whisper, "Creating sparse big file by seeking to end");
+ big_answer = file->methods->seek64(file, big_size, PR_SEEK_SET);
+ if (!LL_EQ(big_answer, big_size)) {
+ return Error("seek", filename);
+ }
+
+ VERBOSE(v_whisper, "Writing block at end of sparse file");
+ bytes = file->methods->write(file, buffer, BUFFER_SIZE);
+ if (bytes != BUFFER_SIZE) {
+ return Error("write", filename);
+ }
+
+ VERBOSE(v_whisper, "Testing available space at end of sparse file");
+ big_answer = file->methods->available64(file);
+ if (!LL_IS_ZERO(big_answer)) {
+ return Error("eof available64()", filename);
+ }
+
+ VERBOSE(v_whisper, "Getting big info on sparse big file");
+ rv = file->methods->fileInfo64(file, &big_info);
+ if (PR_FAILURE == rv) {
+ return Error("fileInfo64()", filename);
+ }
+ if (v_shout <= verbose) {
+ PrintInfo(&big_info, filename);
+ }
+
+ VERBOSE(v_whisper, "Getting small info on sparse big file");
+ rv = file->methods->fileInfo(file, &small_info);
+ if (LL_CMP(sevenFox, <, filesize64) && (PR_SUCCESS == rv))
+ {
+ VERBOSE(v_whisper, "Should have failed and didn't");
+ return Error("fileInfo()", filename);
+ }
+ else if (LL_CMP(sevenFox, >, filesize64) && (PR_FAILURE == rv))
+ {
+ VERBOSE(v_whisper, "Should have succeeded and didn't");
+ return Error("fileInfo()", filename);
+ }
+
+ VERBOSE(v_whisper, "Rewinding big file");
+ big_answer = file->methods->seek64(file, zero_meg, PR_SEEK_SET);
+ if (!LL_IS_ZERO(big_answer)) {
+ return Error("rewind seek64()", filename);
+ }
+
+ VERBOSE(v_whisper, "Establishing available space in rewound file");
+ big_answer = file->methods->available64(file);
+ if (LL_NE(filesize64, big_answer)) {
+ return Error("bof available64()", filename);
+ }
+
+ VERBOSE(v_whisper, "Closing big file");
+ rv = file->methods->close(file);
+ if (PR_FAILURE == rv) {
+ return Error("close()", filename);
+ }
+
+ VERBOSE(v_whisper, "Reopening big file");
+ file = PR_Open(filename, PR_RDWR, 0666);
+ if (NULL == file) {
+ return Error("open failed", filename);
+ }
+
+ VERBOSE(v_whisper, "Checking available data in reopened file");
+ big_answer = file->methods->available64(file);
+ if (LL_NE(filesize64, big_answer)) {
+ return Error("reopened available64()", filename);
+ }
+
+ big_answer = zero_meg;
+ VERBOSE(v_whisper, "Rewriting every byte of big file data");
+ do
+ {
+ bytes = file->methods->write(file, buffer, BUFFER_SIZE);
+ if (bytes != BUFFER_SIZE) {
+ return Error("write", filename);
+ }
+ LL_ADD(big_answer, big_answer, big_fragment);
+ } while (LL_CMP(big_answer, <, filesize64));
+
+ VERBOSE(v_whisper, "Checking position at eof");
+ big_answer = file->methods->seek64(file, zero_meg, PR_SEEK_CUR);
+ if (LL_NE(big_answer, filesize64)) {
+ return Error("file size error", filename);
+ }
+
+ VERBOSE(v_whisper, "Testing available space at eof");
+ big_answer = file->methods->available64(file);
+ if (!LL_IS_ZERO(big_answer)) {
+ return Error("eof available64()", filename);
+ }
+
+ VERBOSE(v_whisper, "Rewinding full file");
+ big_answer = file->methods->seek64(file, zero_meg, PR_SEEK_SET);
+ if (!LL_IS_ZERO(big_answer)) {
+ return Error("bof seek64()", filename);
+ }
+
+ VERBOSE(v_whisper, "Testing available space in rewound file");
+ big_answer = file->methods->available64(file);
+ if (LL_NE(big_answer, filesize64)) {
+ return Error("bof available64()", filename);
+ }
+
+ VERBOSE(v_whisper, "Seeking to end of big file");
+ big_answer = file->methods->seek64(file, filesize64, PR_SEEK_SET);
+ if (LL_NE(big_answer, filesize64)) {
+ return Error("eof seek64()", filename);
+ }
+
+ VERBOSE(v_whisper, "Getting info on big file while it's open");
+ rv = file->methods->fileInfo64(file, &big_info);
+ if (PR_FAILURE == rv) {
+ return Error("fileInfo64()", filename);
+ }
+ if (v_shout <= verbose) {
+ PrintInfo(&big_info, filename);
+ }
+
+ VERBOSE(v_whisper, "Closing big file");
+ rv = file->methods->close(file);
+ if (PR_FAILURE == rv) {
+ return Error("close()", filename);
+ }
+
+ VERBOSE(v_whisper, "Getting info on big file after it's closed");
+ rv = PR_GetFileInfo64(filename, &big_info);
+ if (PR_FAILURE == rv) {
+ return Error("fileInfo64()", filename);
+ }
+ if (v_shout <= verbose) {
+ PrintInfo(&big_info, filename);
+ }
+
+ VERBOSE(v_whisper, "Deleting big file");
+ rv = PR_Delete(filename);
+ if (PR_FAILURE == rv) {
+ return Error("PR_Delete()", filename);
+ }
+
+ PR_DELETE(buffer);
+ return test_result;
+} /* main */
+
+/* bigfile.c */
diff --git a/nsprpub/pr/tests/bigfile2.c b/nsprpub/pr/tests/bigfile2.c
new file mode 100644
index 0000000000..1a7d45b0f5
--- /dev/null
+++ b/nsprpub/pr/tests/bigfile2.c
@@ -0,0 +1,100 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nspr.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef _WIN32
+#include <windows.h>
+#endif
+
+#define TEST_FILE_NAME "bigfile2.txt"
+#ifdef WINCE
+#define TEST_FILE_NAME_FOR_CREATEFILE L"bigfile2.txt"
+#else
+#define TEST_FILE_NAME_FOR_CREATEFILE TEST_FILE_NAME
+#endif
+
+#define MESSAGE "Hello world!"
+#define MESSAGE_SIZE 13
+
+int main(int argc, char **argv)
+{
+ PRFileDesc *fd;
+ PRInt64 offset, position;
+ PRInt32 nbytes;
+ char buf[MESSAGE_SIZE];
+#ifdef _WIN32
+ HANDLE hFile;
+ LARGE_INTEGER li;
+#endif /* _WIN32 */
+
+ LL_I2L(offset, 1);
+ LL_SHL(offset, offset, 32);
+
+ fd = PR_Open(TEST_FILE_NAME,
+ PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, 0666);
+ if (fd == NULL) {
+ fprintf(stderr, "PR_Open failed\n");
+ exit(1);
+ }
+ position = PR_Seek64(fd, offset, PR_SEEK_SET);
+ if (!LL_GE_ZERO(position)) {
+ fprintf(stderr, "PR_Seek64 failed\n");
+ exit(1);
+ }
+ PR_ASSERT(LL_EQ(position, offset));
+ strcpy(buf, MESSAGE);
+ nbytes = PR_Write(fd, buf, sizeof(buf));
+ if (nbytes != sizeof(buf)) {
+ fprintf(stderr, "PR_Write failed\n");
+ exit(1);
+ }
+ if (PR_Close(fd) == PR_FAILURE) {
+ fprintf(stderr, "PR_Close failed\n");
+ exit(1);
+ }
+
+ memset(buf, 0, sizeof(buf));
+
+#ifdef _WIN32
+ hFile = CreateFile(TEST_FILE_NAME_FOR_CREATEFILE, GENERIC_READ, 0, NULL,
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (hFile == INVALID_HANDLE_VALUE) {
+ fprintf(stderr, "CreateFile failed\n");
+ exit(1);
+ }
+ li.QuadPart = offset;
+ li.LowPart = SetFilePointer(hFile, li.LowPart, &li.HighPart, FILE_BEGIN);
+ if (li.LowPart == 0xFFFFFFFF && GetLastError() != NO_ERROR) {
+ fprintf(stderr, "SetFilePointer failed\n");
+ exit(1);
+ }
+ PR_ASSERT(li.QuadPart == offset);
+ if (ReadFile(hFile, buf, sizeof(buf), &nbytes, NULL) == 0) {
+ fprintf(stderr, "ReadFile failed\n");
+ exit(1);
+ }
+ PR_ASSERT(nbytes == sizeof(buf));
+ if (strcmp(buf, MESSAGE)) {
+ fprintf(stderr, "corrupt data:$%s$\n", buf);
+ exit(1);
+ }
+ if (CloseHandle(hFile) == 0) {
+ fprintf(stderr, "CloseHandle failed\n");
+ exit(1);
+ }
+#endif /* _WIN32 */
+
+ if (PR_Delete(TEST_FILE_NAME) == PR_FAILURE) {
+ fprintf(stderr, "PR_Delete failed\n");
+ exit(1);
+ }
+
+ printf("PASS\n");
+ return 0;
+}
diff --git a/nsprpub/pr/tests/bigfile3.c b/nsprpub/pr/tests/bigfile3.c
new file mode 100644
index 0000000000..aeb4d65e41
--- /dev/null
+++ b/nsprpub/pr/tests/bigfile3.c
@@ -0,0 +1,99 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nspr.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef _WIN32
+#include <windows.h>
+#endif
+
+#define TEST_FILE_NAME "bigfile3.txt"
+#ifdef WINCE
+#define TEST_FILE_NAME_FOR_CREATEFILE L"bigfile3.txt"
+#else
+#define TEST_FILE_NAME_FOR_CREATEFILE TEST_FILE_NAME
+#endif
+
+#define MESSAGE "Hello world!"
+#define MESSAGE_SIZE 13
+
+int main(int argc, char **argv)
+{
+ PRFileDesc *fd;
+ PRInt64 offset, position;
+ PRInt32 nbytes;
+ char buf[MESSAGE_SIZE];
+#ifdef _WIN32
+ HANDLE hFile;
+ LARGE_INTEGER li;
+#endif /* _WIN32 */
+
+ LL_I2L(offset, 1);
+ LL_SHL(offset, offset, 32);
+
+#ifdef _WIN32
+ hFile = CreateFile(TEST_FILE_NAME_FOR_CREATEFILE, GENERIC_WRITE, 0, NULL,
+ CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (hFile == INVALID_HANDLE_VALUE) {
+ fprintf(stderr, "CreateFile failed\n");
+ exit(1);
+ }
+ li.QuadPart = offset;
+ li.LowPart = SetFilePointer(hFile, li.LowPart, &li.HighPart, FILE_BEGIN);
+ if (li.LowPart == 0xFFFFFFFF && GetLastError() != NO_ERROR) {
+ fprintf(stderr, "SetFilePointer failed\n");
+ exit(1);
+ }
+ PR_ASSERT(li.QuadPart == offset);
+ strcpy(buf, MESSAGE);
+ if (WriteFile(hFile, buf, sizeof(buf), &nbytes, NULL) == 0) {
+ fprintf(stderr, "WriteFile failed\n");
+ exit(1);
+ }
+ PR_ASSERT(nbytes == sizeof(buf));
+ if (CloseHandle(hFile) == 0) {
+ fprintf(stderr, "CloseHandle failed\n");
+ exit(1);
+ }
+#endif /* _WIN32 */
+
+ memset(buf, 0, sizeof(buf));
+
+ fd = PR_Open(TEST_FILE_NAME, PR_RDONLY, 0666);
+ if (fd == NULL) {
+ fprintf(stderr, "PR_Open failed\n");
+ exit(1);
+ }
+ position = PR_Seek64(fd, offset, PR_SEEK_SET);
+ if (!LL_GE_ZERO(position)) {
+ fprintf(stderr, "PR_Seek64 failed\n");
+ exit(1);
+ }
+ PR_ASSERT(LL_EQ(position, offset));
+ nbytes = PR_Read(fd, buf, sizeof(buf));
+ if (nbytes != sizeof(buf)) {
+ fprintf(stderr, "PR_Read failed\n");
+ exit(1);
+ }
+ if (strcmp(buf, MESSAGE)) {
+ fprintf(stderr, "corrupt data:$%s$\n", buf);
+ exit(1);
+ }
+ if (PR_Close(fd) == PR_FAILURE) {
+ fprintf(stderr, "PR_Close failed\n");
+ exit(1);
+ }
+
+ if (PR_Delete(TEST_FILE_NAME) == PR_FAILURE) {
+ fprintf(stderr, "PR_Delete failed\n");
+ exit(1);
+ }
+
+ printf("PASS\n");
+ return 0;
+}
diff --git a/nsprpub/pr/tests/bug1test.c b/nsprpub/pr/tests/bug1test.c
new file mode 100644
index 0000000000..62ca90d4aa
--- /dev/null
+++ b/nsprpub/pr/tests/bug1test.c
@@ -0,0 +1,230 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+Attached is a test program that uses the nspr1 to demonstrate a bug
+under NT4.0. The fix has already been mentioned (add a ResetEvent just
+before leaving the critical section in _PR_CondWait in hwmon.c).
+*/
+
+#include "prthread.h"
+#include "prtypes.h"
+#include "prinit.h"
+#include "prmon.h"
+#include "prlog.h"
+
+typedef struct Arg_s
+{
+ PRInt32 a, b;
+} Arg_t;
+
+PRMonitor* gMonitor; // the monitor
+PRInt32 gReading; // number of read locks
+PRInt32 gWriteWaiting; // number of threads waiting for write lock
+PRInt32 gReadWaiting; // number of threads waiting for read lock
+
+PRInt32 gCounter; // a counter
+
+// stats
+PRInt32 gReads; // number of successful reads
+PRInt32 gMaxReads; // max number of simultaneous reads
+PRInt32 gMaxWriteWaits; // max number of writes that waited for read
+PRInt32 gMaxReadWaits; // max number of reads that waited for write wait
+
+
+void spin (PRInt32 aDelay)
+{
+ PRInt32 index;
+ PRInt32 delay = aDelay * 1000;
+
+ PR_Sleep(0);
+
+ // randomize delay a bit
+ delay = (delay / 2) + (PRInt32)((float)delay *
+ ((float)rand () / (float)RAND_MAX));
+
+ for (index = 0; index < delay * 10; index++)
+ // consume a bunch of cpu cycles
+ ;
+ PR_Sleep(0);
+}
+
+void doWriteThread (void* arg)
+{
+ PRInt32 last;
+ Arg_t *args = (Arg_t*)arg;
+ PRInt32 aWorkDelay = args->a, aWaitDelay = args->b;
+ PR_Sleep(0);
+
+ while (1)
+ {
+ // -- enter write lock
+ PR_EnterMonitor (gMonitor);
+
+ if (0 < gReading) // wait for read locks to go away
+ {
+ PRIntervalTime fiveSecs = PR_SecondsToInterval(5);
+
+ gWriteWaiting++;
+ if (gWriteWaiting > gMaxWriteWaits) { // stats
+ gMaxWriteWaits = gWriteWaiting;
+ }
+ while (0 < gReading) {
+ PR_Wait (gMonitor, fiveSecs);
+ }
+ gWriteWaiting--;
+ }
+ // -- write lock entered
+
+ last = gCounter;
+ gCounter++;
+
+ spin (aWorkDelay);
+
+ PR_ASSERT (gCounter == (last + 1)); // test invariance
+
+ // -- exit write lock
+// if (0 < gReadWaiting) // notify waiting reads (do it anyway to show off the CondWait bug)
+ PR_NotifyAll (gMonitor);
+
+ PR_ExitMonitor (gMonitor);
+ // -- write lock exited
+
+ spin (aWaitDelay);
+ }
+}
+
+void doReadThread (void* arg)
+{
+ PRInt32 last;
+ Arg_t *args = (Arg_t*)arg;
+ PRInt32 aWorkDelay = args->a, aWaitDelay = args->b;
+ PR_Sleep(0);
+
+ while (1)
+ {
+ // -- enter read lock
+ PR_EnterMonitor (gMonitor);
+
+ if (0 < gWriteWaiting) // give up the monitor to waiting writes
+ {
+ PRIntervalTime fiveSecs = PR_SecondsToInterval(5);
+
+ gReadWaiting++;
+ if (gReadWaiting > gMaxReadWaits) { // stats
+ gMaxReadWaits = gReadWaiting;
+ }
+ while (0 < gWriteWaiting) {
+ PR_Wait (gMonitor, fiveSecs);
+ }
+ gReadWaiting--;
+ }
+
+ gReading++;
+
+ gReads++; // stats
+ if (gReading > gMaxReads) { // stats
+ gMaxReads = gReading;
+ }
+
+ PR_ExitMonitor (gMonitor);
+ // -- read lock entered
+
+ last = gCounter;
+
+ spin (aWorkDelay);
+
+ PR_ASSERT (gCounter == last); // test invariance
+
+ // -- exit read lock
+ PR_EnterMonitor (gMonitor); // read unlock
+ gReading--;
+
+// if ((0 == gReading) && (0 < gWriteWaiting)) // notify waiting writes (do it anyway to show off the CondWait bug)
+ PR_NotifyAll (gMonitor);
+ PR_ExitMonitor (gMonitor);
+ // -- read lock exited
+
+ spin (aWaitDelay);
+ }
+}
+
+
+void fireThread (
+ char* aName, void (*aProc)(void *arg), Arg_t *aArg)
+{
+ PRThread *thread = PR_CreateThread(
+ PR_USER_THREAD, aProc, aArg, PR_PRIORITY_NORMAL,
+ PR_LOCAL_THREAD, PR_UNJOINABLE_THREAD, 0);
+}
+
+int pseudoMain (int argc, char** argv, char *pad)
+{
+ PRInt32 lastWriteCount = gCounter;
+ PRInt32 lastReadCount = gReads;
+ Arg_t a1 = {500, 250};
+ Arg_t a2 = {500, 500};
+ Arg_t a3 = {250, 500};
+ Arg_t a4 = {750, 250};
+ Arg_t a5 = {100, 750};
+ Arg_t a6 = {100, 500};
+ Arg_t a7 = {100, 750};
+
+ gMonitor = PR_NewMonitor ();
+
+ fireThread ("R1", doReadThread, &a1);
+ fireThread ("R2", doReadThread, &a2);
+ fireThread ("R3", doReadThread, &a3);
+ fireThread ("R4", doReadThread, &a4);
+
+ fireThread ("W1", doWriteThread, &a5);
+ fireThread ("W2", doWriteThread, &a6);
+ fireThread ("W3", doWriteThread, &a7);
+
+ fireThread ("R5", doReadThread, &a1);
+ fireThread ("R6", doReadThread, &a2);
+ fireThread ("R7", doReadThread, &a3);
+ fireThread ("R8", doReadThread, &a4);
+
+ fireThread ("W4", doWriteThread, &a5);
+ fireThread ("W5", doWriteThread, &a6);
+ fireThread ("W6", doWriteThread, &a7);
+
+ while (1)
+ {
+ PRInt32 writeCount, readCount;
+ PRIntervalTime fiveSecs = PR_SecondsToInterval(5);
+ PR_Sleep (fiveSecs); // get out of the way
+
+ // print some stats, not threadsafe, informative only
+ writeCount = gCounter;
+ readCount = gReads;
+ printf ("\ntick %d writes (+%d), %d reads (+%d) [max %d, %d, %d]",
+ writeCount, writeCount - lastWriteCount,
+ readCount, readCount - lastReadCount,
+ gMaxReads, gMaxWriteWaits, gMaxReadWaits);
+ lastWriteCount = writeCount;
+ lastReadCount = readCount;
+ gMaxReads = gMaxWriteWaits = gMaxReadWaits = 0;
+ }
+ return 0;
+}
+
+
+static void padStack (int argc, char** argv)
+{
+ char pad[512]; /* Work around bug in nspr on windoze */
+ pseudoMain (argc, argv, pad);
+}
+
+int main(int argc, char **argv)
+{
+ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
+ PR_STDIO_INIT();
+ padStack (argc, argv);
+}
+
+
+/* bug1test.c */
diff --git a/nsprpub/pr/tests/cleanup.c b/nsprpub/pr/tests/cleanup.c
new file mode 100644
index 0000000000..679fe59c92
--- /dev/null
+++ b/nsprpub/pr/tests/cleanup.c
@@ -0,0 +1,103 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "prprf.h"
+#include "prio.h"
+#include "prinit.h"
+#include "prthread.h"
+#include "prinrval.h"
+
+#include "plgetopt.h"
+
+#include <stdlib.h>
+
+static void PR_CALLBACK Thread(void *sleep)
+{
+ PR_Sleep(PR_SecondsToInterval((PRUint32)sleep));
+ printf("Thread exiting\n");
+}
+
+static void Help(void)
+{
+ PRFileDesc *err = PR_GetSpecialFD(PR_StandardError);
+ PR_fprintf(err, "Cleanup usage: [-g] [-s n] [-t n] [-c n] [-h]\n");
+ PR_fprintf(err, "\t-c Call cleanup before exiting (default: false)\n");
+ PR_fprintf(err, "\t-G Use global threads only (default: local)\n");
+ PR_fprintf(err, "\t-t n Number of threads involved (default: 1)\n");
+ PR_fprintf(err, "\t-s n Seconds thread(s) should dally (defaut: 10)\n");
+ PR_fprintf(err, "\t-S n Seconds main() should dally (defaut: 5)\n");
+ PR_fprintf(err, "\t-C n Value to set concurrency (default 1)\n");
+ PR_fprintf(err, "\t-h This message and nothing else\n");
+} /* Help */
+
+int main(int argc, char **argv)
+{
+ PLOptStatus os;
+ PRBool cleanup = PR_FALSE;
+ PRThreadScope type = PR_LOCAL_THREAD;
+ PRFileDesc *err = PR_GetSpecialFD(PR_StandardError);
+ PLOptState *opt = PL_CreateOptState(argc, argv, "Ghs:S:t:cC:");
+ PRIntn concurrency = 1, child_sleep = 10, main_sleep = 5, threads = 1;
+
+ PR_STDIO_INIT();
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 'c': /* call PR_Cleanup() before exiting */
+ cleanup = PR_TRUE;
+ break;
+ case 'G': /* local vs global threads */
+ type = PR_GLOBAL_THREAD;
+ break;
+ case 's': /* time to sleep */
+ child_sleep = atoi(opt->value);
+ break;
+ case 'S': /* time to sleep */
+ main_sleep = atoi(opt->value);
+ break;
+ case 'C': /* number of cpus to create */
+ concurrency = atoi(opt->value);
+ break;
+ case 't': /* number of threads to create */
+ threads = atoi(opt->value);
+ break;
+ case 'h': /* user wants some guidance */
+ Help(); /* so give him an earful */
+ return 2; /* but not a lot else */
+ break;
+ default:
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ PR_fprintf(err, "Cleanup settings\n");
+ PR_fprintf(err, "\tThread type: %s\n",
+ (PR_LOCAL_THREAD == type) ? "LOCAL" : "GLOBAL");
+ PR_fprintf(err, "\tConcurrency: %d\n", concurrency);
+ PR_fprintf(err, "\tNumber of threads: %d\n", threads);
+ PR_fprintf(err, "\tThread sleep: %d\n", child_sleep);
+ PR_fprintf(err, "\tMain sleep: %d\n", main_sleep);
+ PR_fprintf(err, "\tCleanup will %sbe called\n\n", (cleanup) ? "" : "NOT ");
+
+ PR_SetConcurrency(concurrency);
+
+ while (threads-- > 0)
+ (void)PR_CreateThread(
+ PR_USER_THREAD, Thread, (void*)child_sleep, PR_PRIORITY_NORMAL,
+ type, PR_UNJOINABLE_THREAD, 0);
+ PR_Sleep(PR_SecondsToInterval(main_sleep));
+
+ if (cleanup) {
+ PR_Cleanup();
+ }
+
+ PR_fprintf(err, "main() exiting\n");
+ return 0;
+} /* main */
diff --git a/nsprpub/pr/tests/cltsrv.c b/nsprpub/pr/tests/cltsrv.c
new file mode 100644
index 0000000000..2dbe4c7ae9
--- /dev/null
+++ b/nsprpub/pr/tests/cltsrv.c
@@ -0,0 +1,1271 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ *
+ * Notes:
+ * [1] lth. The call to Sleep() is a hack to get the test case to run
+ * on Windows 95. Without it, the test case fails with an error
+ * WSAECONNRESET following a recv() call. The error is caused by the
+ * server side thread termination without a shutdown() or closesocket()
+ * call. Windows docmunentation suggests that this is predicted
+ * behavior; that other platforms get away with it is ... serindipity.
+ * The test case should shutdown() or closesocket() before
+ * thread termination. I didn't have time to figure out where or how
+ * to do it. The Sleep() call inserts enough delay to allow the
+ * client side to recv() all his data before the server side thread
+ * terminates. Whew! ...
+ *
+ ** Modification History:
+ * 14-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
+ * The debug mode will print all of the printfs associated with this test.
+ * The regress mode will be the default mode. Since the regress tool limits
+ * the output to a one line status:PASS or FAIL,all of the printf statements
+ * have been handled with an if (debug_mode) statement.
+ */
+
+#include "prclist.h"
+#include "prcvar.h"
+#include "prerror.h"
+#include "prinit.h"
+#include "prinrval.h"
+#include "prio.h"
+#include "prlock.h"
+#include "prlog.h"
+#include "prtime.h"
+#include "prmem.h"
+#include "prnetdb.h"
+#include "prprf.h"
+#include "prthread.h"
+
+#include "pprio.h"
+#include "primpl.h"
+
+#include "plstr.h"
+#include "plerror.h"
+#include "plgetopt.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#if defined(XP_UNIX)
+#include <math.h>
+#endif
+
+/*
+** This is the beginning of the test
+*/
+
+#define RECV_FLAGS 0
+#define SEND_FLAGS 0
+#define DEFAULT_LOW 0
+#define DEFAULT_HIGH 0
+#define BUFFER_SIZE 1024
+#define DEFAULT_BACKLOG 5
+
+#ifdef DEBUG
+#define PORT_INC_DO +100
+#else
+#define PORT_INC_DO
+#endif
+#ifdef IS_64
+#define PORT_INC_3264 +200
+#else
+#define PORT_INC_3264
+#endif
+
+#define DEFAULT_PORT 12849 PORT_INC_DO PORT_INC_3264
+
+#define DEFAULT_CLIENTS 1
+#define ALLOWED_IN_ACCEPT 1
+#define DEFAULT_CLIPPING 1000
+#define DEFAULT_WORKERS_MIN 1
+#define DEFAULT_WORKERS_MAX 1
+#define DEFAULT_SERVER "localhost"
+#define DEFAULT_EXECUTION_TIME 10
+#define DEFAULT_CLIENT_TIMEOUT 4000
+#define DEFAULT_SERVER_TIMEOUT 4000
+#define DEFAULT_SERVER_PRIORITY PR_PRIORITY_HIGH
+
+typedef enum CSState_e {cs_init, cs_run, cs_stop, cs_exit} CSState_t;
+
+static void PR_CALLBACK Worker(void *arg);
+typedef struct CSPool_s CSPool_t;
+typedef struct CSWorker_s CSWorker_t;
+typedef struct CSServer_s CSServer_t;
+typedef enum Verbosity
+{
+ TEST_LOG_ALWAYS,
+ TEST_LOG_ERROR,
+ TEST_LOG_WARNING,
+ TEST_LOG_NOTICE,
+ TEST_LOG_INFO,
+ TEST_LOG_STATUS,
+ TEST_LOG_VERBOSE
+} Verbosity;
+
+static PRInt32 domain = AF_INET;
+static PRInt32 protocol = 6; /* TCP */
+static PRFileDesc *debug_out = NULL;
+static PRBool debug_mode = PR_FALSE;
+static PRBool pthread_stats = PR_FALSE;
+static Verbosity verbosity = TEST_LOG_ALWAYS;
+static PRThreadScope thread_scope = PR_LOCAL_THREAD;
+
+struct CSWorker_s
+{
+ PRCList element; /* list of the server's workers */
+
+ PRThread *thread; /* this worker objects thread */
+ CSServer_t *server; /* back pointer to server structure */
+};
+
+struct CSPool_s
+{
+ PRCondVar *exiting;
+ PRCondVar *acceptComplete;
+ PRUint32 accepting, active, workers;
+};
+
+struct CSServer_s
+{
+ PRCList list; /* head of worker list */
+
+ PRLock *ml;
+ PRThread *thread; /* the main server thread */
+ PRCondVar *stateChange;
+
+ PRUint16 port; /* port we're listening on */
+ PRUint32 backlog; /* size of our listener backlog */
+ PRFileDesc *listener; /* the fd accepting connections */
+
+ CSPool_t pool; /* statistics on worker threads */
+ CSState_t state; /* the server's state */
+ struct /* controlling worker counts */
+ {
+ PRUint32 minimum, maximum, accepting;
+ } workers;
+
+ /* statistics */
+ PRIntervalTime started, stopped;
+ PRUint32 operations, bytesTransferred;
+};
+
+typedef struct CSDescriptor_s
+{
+ PRInt32 size; /* size of transfer */
+ char filename[60]; /* filename, null padded */
+} CSDescriptor_t;
+
+typedef struct CSClient_s
+{
+ PRLock *ml;
+ PRThread *thread;
+ PRCondVar *stateChange;
+ PRNetAddr serverAddress;
+
+ CSState_t state;
+
+ /* statistics */
+ PRIntervalTime started, stopped;
+ PRUint32 operations, bytesTransferred;
+} CSClient_t;
+
+#define TEST_LOG(l, p, a) \
+ do { \
+ if (debug_mode || (p <= verbosity)) printf a; \
+ } while (0)
+
+PRLogModuleInfo *cltsrv_log_file = NULL;
+
+#define MY_ASSERT(_expr) \
+ ((_expr)?((void)0):_MY_Assert(# _expr,__FILE__,__LINE__))
+
+#define TEST_ASSERT(_expr) \
+ ((_expr)?((void)0):_MY_Assert(# _expr,__FILE__,__LINE__))
+
+static void _MY_Assert(const char *s, const char *file, PRIntn ln)
+{
+ PL_PrintError(NULL);
+ PR_Assert(s, file, ln);
+} /* _MY_Assert */
+
+static PRBool Aborted(PRStatus rv)
+{
+ return ((PR_FAILURE == rv) && (PR_PENDING_INTERRUPT_ERROR == PR_GetError())) ?
+ PR_TRUE : PR_FALSE;
+}
+
+static void TimeOfDayMessage(const char *msg, PRThread* me)
+{
+ char buffer[100];
+ PRExplodedTime tod;
+ PR_ExplodeTime(PR_Now(), PR_LocalTimeParameters, &tod);
+ (void)PR_FormatTime(buffer, sizeof(buffer), "%H:%M:%S", &tod);
+
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_ALWAYS,
+ ("%s(0x%p): %s\n", msg, me, buffer));
+} /* TimeOfDayMessage */
+
+
+static void PR_CALLBACK Client(void *arg)
+{
+ PRStatus rv;
+ PRIntn index;
+ char buffer[1024];
+ PRFileDesc *fd = NULL;
+ PRUintn clipping = DEFAULT_CLIPPING;
+ PRThread *me = PR_GetCurrentThread();
+ CSClient_t *client = (CSClient_t*)arg;
+ CSDescriptor_t *descriptor = PR_NEW(CSDescriptor_t);
+ PRIntervalTime timeout = PR_MillisecondsToInterval(DEFAULT_CLIENT_TIMEOUT);
+
+
+ for (index = 0; index < sizeof(buffer); ++index) {
+ buffer[index] = (char)index;
+ }
+
+ client->started = PR_IntervalNow();
+
+ PR_Lock(client->ml);
+ client->state = cs_run;
+ PR_NotifyCondVar(client->stateChange);
+ PR_Unlock(client->ml);
+
+ TimeOfDayMessage("Client started at", me);
+
+ while (cs_run == client->state)
+ {
+ PRInt32 bytes, descbytes, filebytes, netbytes;
+
+ (void)PR_NetAddrToString(&client->serverAddress, buffer, sizeof(buffer));
+ TEST_LOG(cltsrv_log_file, TEST_LOG_INFO,
+ ("\tClient(0x%p): connecting to server at %s\n", me, buffer));
+
+ fd = PR_Socket(domain, SOCK_STREAM, protocol);
+ TEST_ASSERT(NULL != fd);
+ rv = PR_Connect(fd, &client->serverAddress, timeout);
+ if (PR_FAILURE == rv)
+ {
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_ERROR,
+ ("\tClient(0x%p): conection failed (%d, %d)\n",
+ me, PR_GetError(), PR_GetOSError()));
+ goto aborted;
+ }
+
+ memset(descriptor, 0, sizeof(*descriptor));
+ descriptor->size = PR_htonl(descbytes = rand() % clipping);
+ PR_snprintf(
+ descriptor->filename, sizeof(descriptor->filename),
+ "CS%p%p-%p.dat", client->started, me, client->operations);
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_VERBOSE,
+ ("\tClient(0x%p): sending descriptor for %u bytes\n", me, descbytes));
+ bytes = PR_Send(
+ fd, descriptor, sizeof(*descriptor), SEND_FLAGS, timeout);
+ if (sizeof(CSDescriptor_t) != bytes)
+ {
+ if (Aborted(PR_FAILURE)) {
+ goto aborted;
+ }
+ if (PR_IO_TIMEOUT_ERROR == PR_GetError())
+ {
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_ERROR,
+ ("\tClient(0x%p): send descriptor timeout\n", me));
+ goto retry;
+ }
+ }
+ TEST_ASSERT(sizeof(*descriptor) == bytes);
+
+ netbytes = 0;
+ while (netbytes < descbytes)
+ {
+ filebytes = sizeof(buffer);
+ if ((descbytes - netbytes) < filebytes) {
+ filebytes = descbytes - netbytes;
+ }
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_VERBOSE,
+ ("\tClient(0x%p): sending %d bytes\n", me, filebytes));
+ bytes = PR_Send(fd, buffer, filebytes, SEND_FLAGS, timeout);
+ if (filebytes != bytes)
+ {
+ if (Aborted(PR_FAILURE)) {
+ goto aborted;
+ }
+ if (PR_IO_TIMEOUT_ERROR == PR_GetError())
+ {
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_ERROR,
+ ("\tClient(0x%p): send data timeout\n", me));
+ goto retry;
+ }
+ }
+ TEST_ASSERT(bytes == filebytes);
+ netbytes += bytes;
+ }
+ filebytes = 0;
+ while (filebytes < descbytes)
+ {
+ netbytes = sizeof(buffer);
+ if ((descbytes - filebytes) < netbytes) {
+ netbytes = descbytes - filebytes;
+ }
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_VERBOSE,
+ ("\tClient(0x%p): receiving %d bytes\n", me, netbytes));
+ bytes = PR_Recv(fd, buffer, netbytes, RECV_FLAGS, timeout);
+ if (-1 == bytes)
+ {
+ if (Aborted(PR_FAILURE))
+ {
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_ERROR,
+ ("\tClient(0x%p): receive data aborted\n", me));
+ goto aborted;
+ }
+ else if (PR_IO_TIMEOUT_ERROR == PR_GetError())
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_ERROR,
+ ("\tClient(0x%p): receive data timeout\n", me));
+ else
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_ERROR,
+ ("\tClient(0x%p): receive error (%d, %d)\n",
+ me, PR_GetError(), PR_GetOSError()));
+ goto retry;
+ }
+ if (0 == bytes)
+ {
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_ERROR,
+ ("\t\tClient(0x%p): unexpected end of stream\n",
+ PR_GetCurrentThread()));
+ break;
+ }
+ filebytes += bytes;
+ }
+
+ rv = PR_Shutdown(fd, PR_SHUTDOWN_BOTH);
+ if (Aborted(rv)) {
+ goto aborted;
+ }
+ TEST_ASSERT(PR_SUCCESS == rv);
+retry:
+ (void)PR_Close(fd); fd = NULL;
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_INFO,
+ ("\tClient(0x%p): disconnected from server\n", me));
+
+ PR_Lock(client->ml);
+ client->operations += 1;
+ client->bytesTransferred += 2 * descbytes;
+ rv = PR_WaitCondVar(client->stateChange, rand() % clipping);
+ PR_Unlock(client->ml);
+ if (Aborted(rv)) {
+ break;
+ }
+ }
+
+aborted:
+ client->stopped = PR_IntervalNow();
+
+ PR_ClearInterrupt();
+ if (NULL != fd) {
+ rv = PR_Close(fd);
+ }
+
+ PR_Lock(client->ml);
+ client->state = cs_exit;
+ PR_NotifyCondVar(client->stateChange);
+ PR_Unlock(client->ml);
+ PR_DELETE(descriptor);
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_ALWAYS,
+ ("\tClient(0x%p): stopped after %u operations and %u bytes\n",
+ PR_GetCurrentThread(), client->operations, client->bytesTransferred));
+
+} /* Client */
+
+static PRStatus ProcessRequest(PRFileDesc *fd, CSServer_t *server)
+{
+ PRStatus drv, rv;
+ char buffer[1024];
+ PRFileDesc *file = NULL;
+ PRThread * me = PR_GetCurrentThread();
+ PRInt32 bytes, descbytes, netbytes, filebytes = 0;
+ CSDescriptor_t *descriptor = PR_NEW(CSDescriptor_t);
+ PRIntervalTime timeout = PR_MillisecondsToInterval(DEFAULT_SERVER_TIMEOUT);
+
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_VERBOSE,
+ ("\tProcessRequest(0x%p): receiving desciptor\n", me));
+ bytes = PR_Recv(
+ fd, descriptor, sizeof(*descriptor), RECV_FLAGS, timeout);
+ if (-1 == bytes)
+ {
+ rv = PR_FAILURE;
+ if (Aborted(rv)) {
+ goto exit;
+ }
+ if (PR_IO_TIMEOUT_ERROR == PR_GetError())
+ {
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_ERROR,
+ ("\tProcessRequest(0x%p): receive timeout\n", me));
+ }
+ goto exit;
+ }
+ if (0 == bytes)
+ {
+ rv = PR_FAILURE;
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_ERROR,
+ ("\tProcessRequest(0x%p): unexpected end of file\n", me));
+ goto exit;
+ }
+ descbytes = PR_ntohl(descriptor->size);
+ TEST_ASSERT(sizeof(*descriptor) == bytes);
+
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_VERBOSE,
+ ("\t\tProcessRequest(0x%p): read descriptor {%d, %s}\n",
+ me, descbytes, descriptor->filename));
+
+ file = PR_Open(
+ descriptor->filename, (PR_CREATE_FILE | PR_WRONLY), 0666);
+ if (NULL == file)
+ {
+ rv = PR_FAILURE;
+ if (Aborted(rv)) {
+ goto aborted;
+ }
+ if (PR_IO_TIMEOUT_ERROR == PR_GetError())
+ {
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_ERROR,
+ ("\tProcessRequest(0x%p): open file timeout\n", me));
+ goto aborted;
+ }
+ }
+ TEST_ASSERT(NULL != file);
+
+ filebytes = 0;
+ while (filebytes < descbytes)
+ {
+ netbytes = sizeof(buffer);
+ if ((descbytes - filebytes) < netbytes) {
+ netbytes = descbytes - filebytes;
+ }
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_VERBOSE,
+ ("\tProcessRequest(0x%p): receive %d bytes\n", me, netbytes));
+ bytes = PR_Recv(fd, buffer, netbytes, RECV_FLAGS, timeout);
+ if (-1 == bytes)
+ {
+ rv = PR_FAILURE;
+ if (Aborted(rv)) {
+ goto aborted;
+ }
+ if (PR_IO_TIMEOUT_ERROR == PR_GetError())
+ {
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_ERROR,
+ ("\t\tProcessRequest(0x%p): receive data timeout\n", me));
+ goto aborted;
+ }
+ /*
+ * XXX: I got (PR_CONNECT_RESET_ERROR, ERROR_NETNAME_DELETED)
+ * on NT here. This is equivalent to ECONNRESET on Unix.
+ * -wtc
+ */
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_WARNING,
+ ("\t\tProcessRequest(0x%p): unexpected error (%d, %d)\n",
+ me, PR_GetError(), PR_GetOSError()));
+ goto aborted;
+ }
+ if(0 == bytes)
+ {
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_WARNING,
+ ("\t\tProcessRequest(0x%p): unexpected end of stream\n", me));
+ rv = PR_FAILURE;
+ goto aborted;
+ }
+ filebytes += bytes;
+ netbytes = bytes;
+ /* The byte count for PR_Write should be positive */
+ MY_ASSERT(netbytes > 0);
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_VERBOSE,
+ ("\tProcessRequest(0x%p): write %d bytes to file\n", me, netbytes));
+ bytes = PR_Write(file, buffer, netbytes);
+ if (netbytes != bytes)
+ {
+ rv = PR_FAILURE;
+ if (Aborted(rv)) {
+ goto aborted;
+ }
+ if (PR_IO_TIMEOUT_ERROR == PR_GetError())
+ {
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_ERROR,
+ ("\t\tProcessRequest(0x%p): write file timeout\n", me));
+ goto aborted;
+ }
+ }
+ TEST_ASSERT(bytes > 0);
+ }
+
+ PR_Lock(server->ml);
+ server->operations += 1;
+ server->bytesTransferred += filebytes;
+ PR_Unlock(server->ml);
+
+ rv = PR_Close(file);
+ if (Aborted(rv)) {
+ goto aborted;
+ }
+ TEST_ASSERT(PR_SUCCESS == rv);
+ file = NULL;
+
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_VERBOSE,
+ ("\t\tProcessRequest(0x%p): opening %s\n", me, descriptor->filename));
+ file = PR_Open(descriptor->filename, PR_RDONLY, 0);
+ if (NULL == file)
+ {
+ rv = PR_FAILURE;
+ if (Aborted(rv)) {
+ goto aborted;
+ }
+ if (PR_IO_TIMEOUT_ERROR == PR_GetError())
+ {
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_ERROR,
+ ("\t\tProcessRequest(0x%p): open file timeout\n",
+ PR_GetCurrentThread()));
+ goto aborted;
+ }
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_ERROR,
+ ("\t\tProcessRequest(0x%p): other file open error (%u, %u)\n",
+ me, PR_GetError(), PR_GetOSError()));
+ goto aborted;
+ }
+ TEST_ASSERT(NULL != file);
+
+ netbytes = 0;
+ while (netbytes < descbytes)
+ {
+ filebytes = sizeof(buffer);
+ if ((descbytes - netbytes) < filebytes) {
+ filebytes = descbytes - netbytes;
+ }
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_VERBOSE,
+ ("\tProcessRequest(0x%p): read %d bytes from file\n", me, filebytes));
+ bytes = PR_Read(file, buffer, filebytes);
+ if (filebytes != bytes)
+ {
+ rv = PR_FAILURE;
+ if (Aborted(rv)) {
+ goto aborted;
+ }
+ if (PR_IO_TIMEOUT_ERROR == PR_GetError())
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_ERROR,
+ ("\t\tProcessRequest(0x%p): read file timeout\n", me));
+ else
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_ERROR,
+ ("\t\tProcessRequest(0x%p): other file error (%d, %d)\n",
+ me, PR_GetError(), PR_GetOSError()));
+ goto aborted;
+ }
+ TEST_ASSERT(bytes > 0);
+ netbytes += bytes;
+ filebytes = bytes;
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_VERBOSE,
+ ("\t\tProcessRequest(0x%p): sending %d bytes\n", me, filebytes));
+ bytes = PR_Send(fd, buffer, filebytes, SEND_FLAGS, timeout);
+ if (filebytes != bytes)
+ {
+ rv = PR_FAILURE;
+ if (Aborted(rv)) {
+ goto aborted;
+ }
+ if (PR_IO_TIMEOUT_ERROR == PR_GetError())
+ {
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_ERROR,
+ ("\t\tProcessRequest(0x%p): send data timeout\n", me));
+ goto aborted;
+ }
+ break;
+ }
+ TEST_ASSERT(bytes > 0);
+ }
+
+ PR_Lock(server->ml);
+ server->bytesTransferred += filebytes;
+ PR_Unlock(server->ml);
+
+ rv = PR_Shutdown(fd, PR_SHUTDOWN_BOTH);
+ if (Aborted(rv)) {
+ goto aborted;
+ }
+
+ rv = PR_Close(file);
+ if (Aborted(rv)) {
+ goto aborted;
+ }
+ TEST_ASSERT(PR_SUCCESS == rv);
+ file = NULL;
+
+aborted:
+ PR_ClearInterrupt();
+ if (NULL != file) {
+ PR_Close(file);
+ }
+ drv = PR_Delete(descriptor->filename);
+ TEST_ASSERT(PR_SUCCESS == drv);
+exit:
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_VERBOSE,
+ ("\t\tProcessRequest(0x%p): Finished\n", me));
+
+ PR_DELETE(descriptor);
+
+#if defined(WIN95)
+ PR_Sleep(PR_MillisecondsToInterval(200)); /* lth. see note [1] */
+#endif
+ return rv;
+} /* ProcessRequest */
+
+static PRStatus CreateWorker(CSServer_t *server, CSPool_t *pool)
+{
+ CSWorker_t *worker = PR_NEWZAP(CSWorker_t);
+ worker->server = server;
+ PR_INIT_CLIST(&worker->element);
+ worker->thread = PR_CreateThread(
+ PR_USER_THREAD, Worker, worker,
+ DEFAULT_SERVER_PRIORITY, thread_scope,
+ PR_UNJOINABLE_THREAD, 0);
+ if (NULL == worker->thread)
+ {
+ PR_DELETE(worker);
+ return PR_FAILURE;
+ }
+
+ TEST_LOG(cltsrv_log_file, TEST_LOG_STATUS,
+ ("\tCreateWorker(0x%p): create new worker (0x%p)\n",
+ PR_GetCurrentThread(), worker->thread));
+
+ return PR_SUCCESS;
+} /* CreateWorker */
+
+static void PR_CALLBACK Worker(void *arg)
+{
+ PRStatus rv;
+ PRNetAddr from;
+ PRFileDesc *fd = NULL;
+ PRThread *me = PR_GetCurrentThread();
+ CSWorker_t *worker = (CSWorker_t*)arg;
+ CSServer_t *server = worker->server;
+ CSPool_t *pool = &server->pool;
+
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_NOTICE,
+ ("\t\tWorker(0x%p): started [%u]\n", me, pool->workers + 1));
+
+ PR_Lock(server->ml);
+ PR_APPEND_LINK(&worker->element, &server->list);
+ pool->workers += 1; /* define our existance */
+
+ while (cs_run == server->state)
+ {
+ while (pool->accepting >= server->workers.accepting)
+ {
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_VERBOSE,
+ ("\t\tWorker(0x%p): waiting for accept slot[%d]\n",
+ me, pool->accepting));
+ rv = PR_WaitCondVar(pool->acceptComplete, PR_INTERVAL_NO_TIMEOUT);
+ if (Aborted(rv) || (cs_run != server->state))
+ {
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_NOTICE,
+ ("\tWorker(0x%p): has been %s\n",
+ me, (Aborted(rv) ? "interrupted" : "stopped")));
+ goto exit;
+ }
+ }
+ pool->accepting += 1; /* how many are really in accept */
+ PR_Unlock(server->ml);
+
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_VERBOSE,
+ ("\t\tWorker(0x%p): calling accept\n", me));
+ fd = PR_Accept(server->listener, &from, PR_INTERVAL_NO_TIMEOUT);
+
+ PR_Lock(server->ml);
+ pool->accepting -= 1;
+ PR_NotifyCondVar(pool->acceptComplete);
+
+ if ((NULL == fd) && Aborted(PR_FAILURE))
+ {
+ if (NULL != server->listener)
+ {
+ PR_Close(server->listener);
+ server->listener = NULL;
+ }
+ goto exit;
+ }
+
+ if (NULL != fd)
+ {
+ /*
+ ** Create another worker of the total number of workers is
+ ** less than the minimum specified or we have none left in
+ ** accept() AND we're not over the maximum.
+ ** This sort of presumes that the number allowed in accept
+ ** is at least as many as the minimum. Otherwise we'll keep
+ ** creating new threads and deleting them soon after.
+ */
+ PRBool another =
+ ((pool->workers < server->workers.minimum) ||
+ ((0 == pool->accepting)
+ && (pool->workers < server->workers.maximum))) ?
+ PR_TRUE : PR_FALSE;
+ pool->active += 1;
+ PR_Unlock(server->ml);
+
+ if (another) {
+ (void)CreateWorker(server, pool);
+ }
+
+ rv = ProcessRequest(fd, server);
+ if (PR_SUCCESS != rv)
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_ERROR,
+ ("\t\tWorker(0x%p): server process ended abnormally\n", me));
+ (void)PR_Close(fd); fd = NULL;
+
+ PR_Lock(server->ml);
+ pool->active -= 1;
+ }
+ }
+
+exit:
+ PR_ClearInterrupt();
+ PR_Unlock(server->ml);
+
+ if (NULL != fd)
+ {
+ (void)PR_Shutdown(fd, PR_SHUTDOWN_BOTH);
+ (void)PR_Close(fd);
+ }
+
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_NOTICE,
+ ("\t\tWorker(0x%p): exiting [%u]\n", PR_GetCurrentThread(), pool->workers));
+
+ PR_Lock(server->ml);
+ pool->workers -= 1; /* undefine our existance */
+ PR_REMOVE_AND_INIT_LINK(&worker->element);
+ PR_NotifyCondVar(pool->exiting);
+ PR_Unlock(server->ml);
+
+ PR_DELETE(worker); /* destruction of the "worker" object */
+
+} /* Worker */
+
+static void PR_CALLBACK Server(void *arg)
+{
+ PRStatus rv;
+ PRNetAddr serverAddress;
+ PRThread *me = PR_GetCurrentThread();
+ CSServer_t *server = (CSServer_t*)arg;
+ PRSocketOptionData sockOpt;
+
+ server->listener = PR_Socket(domain, SOCK_STREAM, protocol);
+
+ sockOpt.option = PR_SockOpt_Reuseaddr;
+ sockOpt.value.reuse_addr = PR_TRUE;
+ rv = PR_SetSocketOption(server->listener, &sockOpt);
+ TEST_ASSERT(PR_SUCCESS == rv);
+
+ memset(&serverAddress, 0, sizeof(serverAddress));
+ if (PR_AF_INET6 != domain) {
+ TEST_LOG(cltsrv_log_file, TEST_LOG_ALWAYS,
+ ("server binding to ip port %s\n", DEFAULT_PORT));
+ rv = PR_InitializeNetAddr(PR_IpAddrAny, DEFAULT_PORT, &serverAddress);
+ }
+ else {
+ TEST_LOG(cltsrv_log_file, TEST_LOG_ALWAYS,
+ ("server binding to ipv6 port %s\n", DEFAULT_PORT));
+ rv = PR_SetNetAddr(PR_IpAddrAny, PR_AF_INET6, DEFAULT_PORT,
+ &serverAddress);
+ }
+ rv = PR_Bind(server->listener, &serverAddress);
+ TEST_ASSERT(PR_SUCCESS == rv);
+
+ rv = PR_Listen(server->listener, server->backlog);
+ TEST_ASSERT(PR_SUCCESS == rv);
+
+ server->started = PR_IntervalNow();
+ TimeOfDayMessage("Server started at", me);
+
+ PR_Lock(server->ml);
+ server->state = cs_run;
+ PR_NotifyCondVar(server->stateChange);
+ PR_Unlock(server->ml);
+
+ /*
+ ** Create the first worker (actually, a thread that accepts
+ ** connections and then processes the work load as needed).
+ ** From this point on, additional worker threads are created
+ ** as they are needed by existing worker threads.
+ */
+ rv = CreateWorker(server, &server->pool);
+ TEST_ASSERT(PR_SUCCESS == rv);
+
+ /*
+ ** From here on this thread is merely hanging around as the contact
+ ** point for the main test driver. It's just waiting for the driver
+ ** to declare the test complete.
+ */
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_VERBOSE,
+ ("\tServer(0x%p): waiting for state change\n", me));
+
+ PR_Lock(server->ml);
+ while ((cs_run == server->state) && !Aborted(rv))
+ {
+ rv = PR_WaitCondVar(server->stateChange, PR_INTERVAL_NO_TIMEOUT);
+ }
+ PR_Unlock(server->ml);
+ PR_ClearInterrupt();
+
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_INFO,
+ ("\tServer(0x%p): shutting down workers\n", me));
+
+ /*
+ ** Get all the worker threads to exit. They know how to
+ ** clean up after themselves, so this is just a matter of
+ ** waiting for clorine in the pool to take effect. During
+ ** this stage we're ignoring interrupts.
+ */
+ server->workers.minimum = server->workers.maximum = 0;
+
+ PR_Lock(server->ml);
+ while (!PR_CLIST_IS_EMPTY(&server->list))
+ {
+ PRCList *head = PR_LIST_HEAD(&server->list);
+ CSWorker_t *worker = (CSWorker_t*)head;
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_VERBOSE,
+ ("\tServer(0x%p): interrupting worker(0x%p)\n", me, worker));
+ rv = PR_Interrupt(worker->thread);
+ TEST_ASSERT(PR_SUCCESS == rv);
+ PR_REMOVE_AND_INIT_LINK(head);
+ }
+
+ while (server->pool.workers > 0)
+ {
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_NOTICE,
+ ("\tServer(0x%p): waiting for %u workers to exit\n",
+ me, server->pool.workers));
+ (void)PR_WaitCondVar(server->pool.exiting, PR_INTERVAL_NO_TIMEOUT);
+ }
+
+ server->state = cs_exit;
+ PR_NotifyCondVar(server->stateChange);
+ PR_Unlock(server->ml);
+
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_ALWAYS,
+ ("\tServer(0x%p): stopped after %u operations and %u bytes\n",
+ me, server->operations, server->bytesTransferred));
+
+ if (NULL != server->listener) {
+ PR_Close(server->listener);
+ }
+ server->stopped = PR_IntervalNow();
+
+} /* Server */
+
+static void WaitForCompletion(PRIntn execution)
+{
+ while (execution > 0)
+ {
+ PRIntn dally = (execution > 30) ? 30 : execution;
+ PR_Sleep(PR_SecondsToInterval(dally));
+ if (pthread_stats) {
+ PT_FPrintStats(debug_out, "\nPThread Statistics\n");
+ }
+ execution -= dally;
+ }
+} /* WaitForCompletion */
+
+static void Help(void)
+{
+ PR_fprintf(debug_out, "cltsrv test program usage:\n");
+ PR_fprintf(debug_out, "\t-a <n> threads allowed in accept (5)\n");
+ PR_fprintf(debug_out, "\t-b <n> backlock for listen (5)\n");
+ PR_fprintf(debug_out, "\t-c <threads> number of clients to create (1)\n");
+ PR_fprintf(debug_out, "\t-f <low> low water mark for fd caching (0)\n");
+ PR_fprintf(debug_out, "\t-F <high> high water mark for fd caching (0)\n");
+ PR_fprintf(debug_out, "\t-w <threads> minimal number of server threads (1)\n");
+ PR_fprintf(debug_out, "\t-W <threads> maximum number of server threads (1)\n");
+ PR_fprintf(debug_out, "\t-e <seconds> duration of the test in seconds (10)\n");
+ PR_fprintf(debug_out, "\t-s <string> dsn name of server (localhost)\n");
+ PR_fprintf(debug_out, "\t-G use GLOBAL threads (LOCAL)\n");
+ PR_fprintf(debug_out, "\t-X use XTP as transport (TCP)\n");
+ PR_fprintf(debug_out, "\t-6 Use IPv6 (IPv4)\n");
+ PR_fprintf(debug_out, "\t-v verbosity (accumulative) (0)\n");
+ PR_fprintf(debug_out, "\t-p pthread statistics (FALSE)\n");
+ PR_fprintf(debug_out, "\t-d debug mode (FALSE)\n");
+ PR_fprintf(debug_out, "\t-h this message\n");
+} /* Help */
+
+static Verbosity IncrementVerbosity(void)
+{
+ PRIntn verboge = (PRIntn)verbosity + 1;
+ return (Verbosity)verboge;
+} /* IncrementVerbosity */
+
+int main(int argc, char** argv)
+{
+ PRUintn index;
+ PRBool boolean;
+ CSClient_t *client;
+ PRStatus rv, joinStatus;
+ CSServer_t *server = NULL;
+
+ PRUintn backlog = DEFAULT_BACKLOG;
+ PRUintn clients = DEFAULT_CLIENTS;
+ const char *serverName = DEFAULT_SERVER;
+ PRBool serverIsLocal = PR_TRUE;
+ PRUintn accepting = ALLOWED_IN_ACCEPT;
+ PRUintn workersMin = DEFAULT_WORKERS_MIN;
+ PRUintn workersMax = DEFAULT_WORKERS_MAX;
+ PRIntn execution = DEFAULT_EXECUTION_TIME;
+ PRIntn low = DEFAULT_LOW, high = DEFAULT_HIGH;
+
+ /*
+ * -G use global threads
+ * -a <n> threads allowed in accept
+ * -b <n> backlock for listen
+ * -c <threads> number of clients to create
+ * -f <low> low water mark for caching FDs
+ * -F <high> high water mark for caching FDs
+ * -w <threads> minimal number of server threads
+ * -W <threads> maximum number of server threads
+ * -e <seconds> duration of the test in seconds
+ * -s <string> dsn name of server (implies no server here)
+ * -v verbosity
+ */
+
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "GX6b:a:c:f:F:w:W:e:s:vdhp");
+
+ debug_out = PR_GetSpecialFD(PR_StandardError);
+
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 'G': /* use global threads */
+ thread_scope = PR_GLOBAL_THREAD;
+ break;
+ case 'X': /* use XTP as transport */
+ protocol = 36;
+ break;
+ case '6': /* Use IPv6 */
+ domain = PR_AF_INET6;
+ break;
+ case 'a': /* the value for accepting */
+ accepting = atoi(opt->value);
+ break;
+ case 'b': /* the value for backlock */
+ backlog = atoi(opt->value);
+ break;
+ case 'c': /* number of client threads */
+ clients = atoi(opt->value);
+ break;
+ case 'f': /* low water fd cache */
+ low = atoi(opt->value);
+ break;
+ case 'F': /* low water fd cache */
+ high = atoi(opt->value);
+ break;
+ case 'w': /* minimum server worker threads */
+ workersMin = atoi(opt->value);
+ break;
+ case 'W': /* maximum server worker threads */
+ workersMax = atoi(opt->value);
+ break;
+ case 'e': /* program execution time in seconds */
+ execution = atoi(opt->value);
+ break;
+ case 's': /* server's address */
+ serverName = opt->value;
+ break;
+ case 'v': /* verbosity */
+ verbosity = IncrementVerbosity();
+ break;
+ case 'd': /* debug mode */
+ debug_mode = PR_TRUE;
+ break;
+ case 'p': /* pthread mode */
+ pthread_stats = PR_TRUE;
+ break;
+ case 'h':
+ default:
+ Help();
+ return 2;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ if (0 != PL_strcmp(serverName, DEFAULT_SERVER)) {
+ serverIsLocal = PR_FALSE;
+ }
+ if (0 == execution) {
+ execution = DEFAULT_EXECUTION_TIME;
+ }
+ if (0 == workersMax) {
+ workersMax = DEFAULT_WORKERS_MAX;
+ }
+ if (0 == workersMin) {
+ workersMin = DEFAULT_WORKERS_MIN;
+ }
+ if (0 == accepting) {
+ accepting = ALLOWED_IN_ACCEPT;
+ }
+ if (0 == backlog) {
+ backlog = DEFAULT_BACKLOG;
+ }
+
+ if (workersMin > accepting) {
+ accepting = workersMin;
+ }
+
+ PR_STDIO_INIT();
+ TimeOfDayMessage("Client/Server started at", PR_GetCurrentThread());
+
+ cltsrv_log_file = PR_NewLogModule("cltsrv_log");
+ MY_ASSERT(NULL != cltsrv_log_file);
+ boolean = PR_SetLogFile("cltsrv.log");
+ MY_ASSERT(boolean);
+
+ rv = PR_SetFDCacheSize(low, high);
+ PR_ASSERT(PR_SUCCESS == rv);
+
+ if (serverIsLocal)
+ {
+ /* Establish the server */
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_INFO,
+ ("main(0x%p): starting server\n", PR_GetCurrentThread()));
+
+ server = PR_NEWZAP(CSServer_t);
+ PR_INIT_CLIST(&server->list);
+ server->state = cs_init;
+ server->ml = PR_NewLock();
+ server->backlog = backlog;
+ server->port = DEFAULT_PORT;
+ server->workers.minimum = workersMin;
+ server->workers.maximum = workersMax;
+ server->workers.accepting = accepting;
+ server->stateChange = PR_NewCondVar(server->ml);
+ server->pool.exiting = PR_NewCondVar(server->ml);
+ server->pool.acceptComplete = PR_NewCondVar(server->ml);
+
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_NOTICE,
+ ("main(0x%p): creating server thread\n", PR_GetCurrentThread()));
+
+ server->thread = PR_CreateThread(
+ PR_USER_THREAD, Server, server, PR_PRIORITY_HIGH,
+ thread_scope, PR_JOINABLE_THREAD, 0);
+ TEST_ASSERT(NULL != server->thread);
+
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_VERBOSE,
+ ("main(0x%p): waiting for server init\n", PR_GetCurrentThread()));
+
+ PR_Lock(server->ml);
+ while (server->state == cs_init) {
+ PR_WaitCondVar(server->stateChange, PR_INTERVAL_NO_TIMEOUT);
+ }
+ PR_Unlock(server->ml);
+
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_VERBOSE,
+ ("main(0x%p): server init complete (port #%d)\n",
+ PR_GetCurrentThread(), server->port));
+ }
+
+ if (clients != 0)
+ {
+ /* Create all of the clients */
+ PRHostEnt host;
+ char buffer[BUFFER_SIZE];
+ client = (CSClient_t*)PR_CALLOC(clients * sizeof(CSClient_t));
+
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_VERBOSE,
+ ("main(0x%p): creating %d client threads\n",
+ PR_GetCurrentThread(), clients));
+
+ if (!serverIsLocal)
+ {
+ rv = PR_GetHostByName(serverName, buffer, BUFFER_SIZE, &host);
+ if (PR_SUCCESS != rv)
+ {
+ PL_FPrintError(PR_STDERR, "PR_GetHostByName");
+ return 2;
+ }
+ }
+
+ for (index = 0; index < clients; ++index)
+ {
+ client[index].state = cs_init;
+ client[index].ml = PR_NewLock();
+ if (serverIsLocal)
+ {
+ if (PR_AF_INET6 != domain) {
+ TEST_LOG(cltsrv_log_file, TEST_LOG_ALWAYS,
+ ("loopback client ip port %s\n", DEFAULT_PORT));
+ (void)PR_InitializeNetAddr(
+ PR_IpAddrLoopback, DEFAULT_PORT,
+ &client[index].serverAddress);
+ }
+ else {
+ TEST_LOG(cltsrv_log_file, TEST_LOG_ALWAYS,
+ ("loopback client ipv6 port %s\n", DEFAULT_PORT));
+ rv = PR_SetNetAddr(PR_IpAddrLoopback, PR_AF_INET6,
+ DEFAULT_PORT, &client[index].serverAddress);
+ }
+ }
+ else
+ {
+ TEST_LOG(cltsrv_log_file, TEST_LOG_ALWAYS,
+ ("client enumerate port %s\n", DEFAULT_PORT));
+ (void)PR_EnumerateHostEnt(
+ 0, &host, DEFAULT_PORT, &client[index].serverAddress);
+ }
+ client[index].stateChange = PR_NewCondVar(client[index].ml);
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_INFO,
+ ("main(0x%p): creating client threads\n", PR_GetCurrentThread()));
+ client[index].thread = PR_CreateThread(
+ PR_USER_THREAD, Client, &client[index], PR_PRIORITY_NORMAL,
+ thread_scope, PR_JOINABLE_THREAD, 0);
+ TEST_ASSERT(NULL != client[index].thread);
+ PR_Lock(client[index].ml);
+ while (cs_init == client[index].state) {
+ PR_WaitCondVar(client[index].stateChange, PR_INTERVAL_NO_TIMEOUT);
+ }
+ PR_Unlock(client[index].ml);
+ }
+ }
+
+ /* Then just let them go at it for a bit */
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_ALWAYS,
+ ("main(0x%p): waiting for execution interval (%d seconds)\n",
+ PR_GetCurrentThread(), execution));
+
+ WaitForCompletion(execution);
+
+ TimeOfDayMessage("Shutting down", PR_GetCurrentThread());
+
+ if (clients != 0)
+ {
+ for (index = 0; index < clients; ++index)
+ {
+ TEST_LOG(cltsrv_log_file, TEST_LOG_STATUS,
+ ("main(0x%p): notifying client(0x%p) to stop\n",
+ PR_GetCurrentThread(), client[index].thread));
+
+ PR_Lock(client[index].ml);
+ if (cs_run == client[index].state)
+ {
+ client[index].state = cs_stop;
+ PR_Interrupt(client[index].thread);
+ while (cs_stop == client[index].state)
+ PR_WaitCondVar(
+ client[index].stateChange, PR_INTERVAL_NO_TIMEOUT);
+ }
+ PR_Unlock(client[index].ml);
+
+ TEST_LOG(cltsrv_log_file, TEST_LOG_VERBOSE,
+ ("main(0x%p): joining client(0x%p)\n",
+ PR_GetCurrentThread(), client[index].thread));
+
+ joinStatus = PR_JoinThread(client[index].thread);
+ TEST_ASSERT(PR_SUCCESS == joinStatus);
+ PR_DestroyCondVar(client[index].stateChange);
+ PR_DestroyLock(client[index].ml);
+ }
+ PR_DELETE(client);
+ }
+
+ if (NULL != server)
+ {
+ /* All clients joined - retrieve the server */
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_NOTICE,
+ ("main(0x%p): notifying server(0x%p) to stop\n",
+ PR_GetCurrentThread(), server->thread));
+
+ PR_Lock(server->ml);
+ server->state = cs_stop;
+ PR_Interrupt(server->thread);
+ while (cs_exit != server->state) {
+ PR_WaitCondVar(server->stateChange, PR_INTERVAL_NO_TIMEOUT);
+ }
+ PR_Unlock(server->ml);
+
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_NOTICE,
+ ("main(0x%p): joining server(0x%p)\n",
+ PR_GetCurrentThread(), server->thread));
+ joinStatus = PR_JoinThread(server->thread);
+ TEST_ASSERT(PR_SUCCESS == joinStatus);
+
+ PR_DestroyCondVar(server->stateChange);
+ PR_DestroyCondVar(server->pool.exiting);
+ PR_DestroyCondVar(server->pool.acceptComplete);
+ PR_DestroyLock(server->ml);
+ PR_DELETE(server);
+ }
+
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_ALWAYS,
+ ("main(0x%p): test complete\n", PR_GetCurrentThread()));
+
+ PT_FPrintStats(debug_out, "\nPThread Statistics\n");
+
+ TimeOfDayMessage("Test exiting at", PR_GetCurrentThread());
+ PR_Cleanup();
+ return 0;
+} /* main */
+
+/* cltsrv.c */
diff --git a/nsprpub/pr/tests/concur.c b/nsprpub/pr/tests/concur.c
new file mode 100644
index 0000000000..5940290213
--- /dev/null
+++ b/nsprpub/pr/tests/concur.c
@@ -0,0 +1,166 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+** File: concur.c
+** Description: test of adding and removing concurrency options
+*/
+
+#include "prcvar.h"
+#include "prinit.h"
+#include "prinrval.h"
+#include "prlock.h"
+#include "prprf.h"
+#include "prmem.h"
+#include "prlog.h"
+
+#include "plgetopt.h"
+
+#include "private/pprio.h"
+
+#include <stdlib.h>
+
+#define DEFAULT_RANGE 10
+#define DEFAULT_LOOPS 100
+
+static PRThreadScope thread_scope = PR_LOCAL_THREAD;
+
+typedef struct Context
+{
+ PRLock *ml;
+ PRCondVar *cv;
+ PRIntn want, have;
+} Context;
+
+
+/*
+** Make the instance of 'context' static (not on the stack)
+** for Win16 threads
+*/
+static Context context = {NULL, NULL, 0, 0};
+
+static void PR_CALLBACK Dull(void *arg)
+{
+ Context *context = (Context*)arg;
+ PR_Lock(context->ml);
+ context->have += 1;
+ while (context->want >= context->have) {
+ PR_WaitCondVar(context->cv, PR_INTERVAL_NO_TIMEOUT);
+ }
+ context->have -= 1;
+ PR_Unlock(context->ml);
+} /* Dull */
+
+PRIntn PR_CALLBACK Concur(PRIntn argc, char **argv)
+{
+ PRUintn cpus;
+ PLOptStatus os;
+ PRThread **threads;
+ PRBool debug = PR_FALSE;
+ PRUintn range = DEFAULT_RANGE;
+ PRStatus rc;
+ PRUintn cnt;
+ PRUintn loops = DEFAULT_LOOPS;
+ PRIntervalTime hundredMills = PR_MillisecondsToInterval(100);
+ PLOptState *opt = PL_CreateOptState(argc, argv, "Gdl:r:");
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 'G': /* GLOBAL threads */
+ thread_scope = PR_GLOBAL_THREAD;
+ break;
+ case 'd': /* debug mode */
+ debug = PR_TRUE;
+ break;
+ case 'r': /* range limit */
+ range = atoi(opt->value);
+ break;
+ case 'l': /* loop counter */
+ loops = atoi(opt->value);
+ break;
+ default:
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ if (0 == range) {
+ range = DEFAULT_RANGE;
+ }
+ if (0 == loops) {
+ loops = DEFAULT_LOOPS;
+ }
+
+ context.ml = PR_NewLock();
+ context.cv = PR_NewCondVar(context.ml);
+
+ if (debug)
+ PR_fprintf(
+ PR_STDERR, "Testing with %d CPUs and %d interations\n", range, loops);
+
+ threads = (PRThread**) PR_CALLOC(sizeof(PRThread*) * range);
+ while (--loops > 0)
+ {
+ for (cpus = 1; cpus <= range; ++cpus)
+ {
+ PR_SetConcurrency(cpus);
+ context.want = cpus;
+
+ threads[cpus - 1] = PR_CreateThread(
+ PR_USER_THREAD, Dull, &context, PR_PRIORITY_NORMAL,
+ thread_scope, PR_JOINABLE_THREAD, 0);
+ }
+
+ PR_Sleep(hundredMills);
+
+ for (cpus = range; cpus > 0; cpus--)
+ {
+ PR_SetConcurrency(cpus);
+ context.want = cpus - 1;
+
+ PR_Lock(context.ml);
+ PR_NotifyCondVar(context.cv);
+ PR_Unlock(context.ml);
+ }
+ for(cnt = 0; cnt < range; cnt++) {
+ rc = PR_JoinThread(threads[cnt]);
+ PR_ASSERT(rc == PR_SUCCESS);
+ }
+ }
+
+
+ if (debug)
+ PR_fprintf(
+ PR_STDERR, "Waiting for %d thread(s) to exit\n", context.have);
+
+ while (context.have > 0) {
+ PR_Sleep(hundredMills);
+ }
+
+ if (debug)
+ PR_fprintf(
+ PR_STDERR, "Finished [want: %d, have: %d]\n",
+ context.want, context.have);
+
+ PR_DestroyLock(context.ml);
+ PR_DestroyCondVar(context.cv);
+ PR_DELETE(threads);
+
+ PR_fprintf(PR_STDERR, "PASSED\n");
+
+ return 0;
+} /* Concur */
+
+int main(int argc, char **argv)
+{
+ PR_STDIO_INIT();
+ return PR_Initialize(Concur, argc, argv, 0);
+} /* main */
+
+/* concur.c */
diff --git a/nsprpub/pr/tests/cvar.c b/nsprpub/pr/tests/cvar.c
new file mode 100644
index 0000000000..4dc891d3f9
--- /dev/null
+++ b/nsprpub/pr/tests/cvar.c
@@ -0,0 +1,309 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/***********************************************************************
+** 1996 - Netscape Communications Corporation
+**
+** Name: cvar.c
+**
+** Description: Tests Condition Variable Operations
+**
+** Modification History:
+** 13-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
+** The debug mode will print all of the printfs associated with this test.
+** The regress mode will be the default mode. Since the regress tool limits
+** the output to a one line status:PASS or FAIL,all of the printf statements
+** have been handled with an if (debug_mode) statement.
+** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to
+** recognize the return code from tha main program.
+** 12-June-97 Revert to return code 0 and 1.
+***********************************************************************/
+
+/***********************************************************************
+** Includes
+***********************************************************************/
+
+#include "nspr.h"
+
+/* Used to get the command line option */
+#include "plgetopt.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+PRMonitor *mon;
+#define DEFAULT_COUNT 1000
+PRInt32 count = 0;
+PRIntn debug_mode;
+
+#define kQSIZE 1
+
+typedef struct {
+ PRLock *bufLock;
+ int startIdx;
+ int numFull;
+ PRCondVar *notFull;
+ PRCondVar *notEmpty;
+ void *data[kQSIZE];
+} CircBuf;
+
+static PRBool failed = PR_FALSE;
+
+/*
+** NewCB creates and initializes a new circular buffer.
+*/
+static CircBuf* NewCB(void)
+{
+ CircBuf *cbp;
+
+ cbp = PR_NEW(CircBuf);
+ if (cbp == NULL) {
+ return (NULL);
+ }
+
+ cbp->bufLock = PR_NewLock();
+ cbp->startIdx = 0;
+ cbp->numFull = 0;
+ cbp->notFull = PR_NewCondVar(cbp->bufLock);
+ cbp->notEmpty = PR_NewCondVar(cbp->bufLock);
+
+ return (cbp);
+}
+
+/*
+** DeleteCB frees a circular buffer.
+*/
+static void DeleteCB(CircBuf *cbp)
+{
+ PR_DestroyLock(cbp->bufLock);
+ PR_DestroyCondVar(cbp->notFull);
+ PR_DestroyCondVar(cbp->notEmpty);
+ PR_DELETE(cbp);
+}
+
+
+/*
+** PutCBData puts new data on the queue. If the queue is full, it waits
+** until there is room.
+*/
+static void PutCBData(CircBuf *cbp, void *data)
+{
+ PR_Lock(cbp->bufLock);
+ /* wait while the buffer is full */
+ while (cbp->numFull == kQSIZE) {
+ PR_WaitCondVar(cbp->notFull,PR_INTERVAL_NO_TIMEOUT);
+ }
+ cbp->data[(cbp->startIdx + cbp->numFull) % kQSIZE] = data;
+ cbp->numFull += 1;
+
+ /* let a waiting reader know that there is data */
+ PR_NotifyCondVar(cbp->notEmpty);
+ PR_Unlock(cbp->bufLock);
+
+}
+
+
+/*
+** GetCBData gets the oldest data on the queue. If the queue is empty, it waits
+** until new data appears.
+*/
+static void* GetCBData(CircBuf *cbp)
+{
+ void *data;
+
+ PR_Lock(cbp->bufLock);
+ /* wait while the buffer is empty */
+ while (cbp->numFull == 0) {
+ PR_WaitCondVar(cbp->notEmpty,PR_INTERVAL_NO_TIMEOUT);
+ }
+ data = cbp->data[cbp->startIdx];
+ cbp->startIdx =(cbp->startIdx + 1) % kQSIZE;
+ cbp->numFull -= 1;
+
+ /* let a waiting writer know that there is room */
+ PR_NotifyCondVar(cbp->notFull);
+ PR_Unlock(cbp->bufLock);
+
+ return (data);
+}
+
+
+/************************************************************************/
+
+static int alive;
+
+static void PR_CALLBACK CXReader(void *arg)
+{
+ CircBuf *cbp = (CircBuf *)arg;
+ PRInt32 i, n;
+ void *data;
+
+ n = count / 2;
+ for (i = 0; i < n; i++) {
+ data = GetCBData(cbp);
+ if ((int)data != i)
+ if (debug_mode) {
+ printf("data mismatch at for i = %d usec\n", i);
+ }
+ }
+
+ PR_EnterMonitor(mon);
+ --alive;
+ PR_Notify(mon);
+ PR_ExitMonitor(mon);
+}
+
+static void PR_CALLBACK CXWriter(void *arg)
+{
+ CircBuf *cbp = (CircBuf *)arg;
+ PRInt32 i, n;
+
+ n = count / 2;
+ for (i = 0; i < n; i++) {
+ PutCBData(cbp, (void *)i);
+ }
+
+ PR_EnterMonitor(mon);
+ --alive;
+ PR_Notify(mon);
+ PR_ExitMonitor(mon);
+}
+
+static void CondWaitContextSwitch(PRThreadScope scope1, PRThreadScope scope2)
+{
+ PRThread *t1, *t2;
+ CircBuf *cbp;
+
+ PR_EnterMonitor(mon);
+
+ alive = 2;
+
+ cbp = NewCB();
+
+ t1 = PR_CreateThread(PR_USER_THREAD,
+ CXReader, cbp,
+ PR_PRIORITY_NORMAL,
+ scope1,
+ PR_UNJOINABLE_THREAD,
+ 0);
+ PR_ASSERT(t1);
+ t2 = PR_CreateThread(PR_USER_THREAD,
+ CXWriter, cbp,
+ PR_PRIORITY_NORMAL,
+ scope2,
+ PR_UNJOINABLE_THREAD,
+ 0);
+ PR_ASSERT(t2);
+
+ /* Wait for both of the threads to exit */
+ while (alive) {
+ PR_Wait(mon, PR_INTERVAL_NO_TIMEOUT);
+ }
+
+ DeleteCB(cbp);
+
+ PR_ExitMonitor(mon);
+}
+
+static void CondWaitContextSwitchUU(void)
+{
+ CondWaitContextSwitch(PR_LOCAL_THREAD, PR_LOCAL_THREAD);
+}
+
+static void CondWaitContextSwitchUK(void)
+{
+ CondWaitContextSwitch(PR_LOCAL_THREAD, PR_GLOBAL_THREAD);
+}
+
+static void CondWaitContextSwitchKK(void)
+{
+ CondWaitContextSwitch(PR_GLOBAL_THREAD, PR_GLOBAL_THREAD);
+}
+
+/************************************************************************/
+
+static void Measure(void (*func)(void), const char *msg)
+{
+ PRIntervalTime start, stop;
+ double d;
+
+ start = PR_IntervalNow();
+ (*func)();
+ stop = PR_IntervalNow();
+
+ d = (double)PR_IntervalToMicroseconds(stop - start);
+
+ if (debug_mode) {
+ printf("%40s: %6.2f usec\n", msg, d / count);
+ }
+
+ if (0 == d) {
+ failed = PR_TRUE;
+ }
+}
+
+static PRIntn PR_CALLBACK RealMain(int argc, char **argv)
+{
+ /* The command line argument: -d is used to determine if the test is being run
+ in debug mode. The regress tool requires only one line output:PASS or FAIL.
+ All of the printfs associated with this test has been handled with a if (debug_mode)
+ test.
+ Usage: test_name [-d] [-c n]
+ */
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "dc:");
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 'd': /* debug mode */
+ debug_mode = 1;
+ break;
+ case 'c': /* loop count */
+ count = atoi(opt->value);
+ break;
+ default:
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ if (0 == count) {
+ count = DEFAULT_COUNT;
+ }
+
+ mon = PR_NewMonitor();
+
+ Measure(CondWaitContextSwitchUU, "cond var wait context switch- user/user");
+ Measure(CondWaitContextSwitchUK, "cond var wait context switch- user/kernel");
+ Measure(CondWaitContextSwitchKK, "cond var wait context switch- kernel/kernel");
+
+ PR_DestroyMonitor(mon);
+
+ if (debug_mode) {
+ printf("%s\n", (failed) ? "FAILED" : "PASSED");
+ }
+
+ if(failed) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+}
+
+
+int main(int argc, char *argv[])
+{
+ PRIntn rv;
+
+ PR_STDIO_INIT();
+ rv = PR_Initialize(RealMain, argc, argv, 0);
+ return rv;
+} /* main */
diff --git a/nsprpub/pr/tests/cvar2.c b/nsprpub/pr/tests/cvar2.c
new file mode 100644
index 0000000000..c9f57d5cc6
--- /dev/null
+++ b/nsprpub/pr/tests/cvar2.c
@@ -0,0 +1,976 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/***********************************************************************
+** 1996 - Netscape Communications Corporation
+**
+** Name: cvar2.c
+**
+** Description: Simple test creates several local and global threads;
+** half use a single,shared condvar, and the
+** other half have their own condvar. The main thread then loops
+** notifying them to wakeup.
+**
+** Modification History:
+** 14-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
+** The debug mode will print all of the printfs associated with this test.
+** The regress mode will be the default mode. Since the regress tool limits
+** the output to a one line status:PASS or FAIL,all of the printf statements
+** have been handled with an if (debug_mode) statement.
+***********************************************************************/
+
+#include "nspr.h"
+#include "plerror.h"
+#include "plgetopt.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int _debug_on = 0;
+#define DPRINTF(arg) if (_debug_on) printf arg
+
+#define DEFAULT_COUNT 100
+#define DEFAULT_THREADS 5
+PRInt32 count = DEFAULT_COUNT;
+
+typedef struct threadinfo {
+ PRThread *thread;
+ PRInt32 id;
+ PRBool internal;
+ PRInt32 *tcount;
+ PRLock *lock;
+ PRCondVar *cvar;
+ PRIntervalTime timeout;
+ PRInt32 loops;
+
+ PRLock *exitlock;
+ PRCondVar *exitcvar;
+ PRInt32 *exitcount;
+} threadinfo;
+
+/*
+** Make exitcount, tcount static. for Win16.
+*/
+static PRInt32 exitcount=0;
+static PRInt32 tcount=0;
+
+
+/* Thread that gets notified; many threads share the same condvar */
+void PR_CALLBACK
+SharedCondVarThread(void *_info)
+{
+ threadinfo *info = (threadinfo *)_info;
+ PRInt32 index;
+
+ for (index=0; index<info->loops; index++) {
+ PR_Lock(info->lock);
+ if (*info->tcount == 0) {
+ PR_WaitCondVar(info->cvar, info->timeout);
+ }
+#if 0
+ printf("shared thread %ld notified in loop %ld\n", info->id, index);
+#endif
+ (*info->tcount)--;
+ PR_Unlock(info->lock);
+
+ PR_Lock(info->exitlock);
+ (*info->exitcount)++;
+ PR_NotifyCondVar(info->exitcvar);
+ PR_Unlock(info->exitlock);
+ }
+#if 0
+ printf("shared thread %ld terminating\n", info->id);
+#endif
+}
+
+/* Thread that gets notified; no other threads use the same condvar */
+void PR_CALLBACK
+PrivateCondVarThread(void *_info)
+{
+ threadinfo *info = (threadinfo *)_info;
+ PRInt32 index;
+
+ for (index=0; index<info->loops; index++) {
+ PR_Lock(info->lock);
+ if (*info->tcount == 0) {
+ DPRINTF(("PrivateCondVarThread: thread 0x%lx waiting on cvar = 0x%lx\n",
+ PR_GetCurrentThread(), info->cvar));
+ PR_WaitCondVar(info->cvar, info->timeout);
+ }
+#if 0
+ printf("solo thread %ld notified in loop %ld\n", info->id, index);
+#endif
+ (*info->tcount)--;
+ PR_Unlock(info->lock);
+
+ PR_Lock(info->exitlock);
+ (*info->exitcount)++;
+ PR_NotifyCondVar(info->exitcvar);
+ DPRINTF(("PrivateCondVarThread: thread 0x%lx notified exitcvar = 0x%lx cnt = %ld\n",
+ PR_GetCurrentThread(), info->exitcvar,(*info->exitcount)));
+ PR_Unlock(info->exitlock);
+ }
+#if 0
+ printf("solo thread %ld terminating\n", info->id);
+#endif
+}
+
+void
+CreateTestThread(threadinfo *info,
+ PRInt32 id,
+ PRLock *lock,
+ PRCondVar *cvar,
+ PRInt32 loops,
+ PRIntervalTime timeout,
+ PRInt32 *tcount,
+ PRLock *exitlock,
+ PRCondVar *exitcvar,
+ PRInt32 *exitcount,
+ PRBool shared,
+ PRThreadScope scope)
+{
+ info->id = id;
+ info->internal = (shared) ? PR_FALSE : PR_TRUE;
+ info->lock = lock;
+ info->cvar = cvar;
+ info->loops = loops;
+ info->timeout = timeout;
+ info->tcount = tcount;
+ info->exitlock = exitlock;
+ info->exitcvar = exitcvar;
+ info->exitcount = exitcount;
+ info->thread = PR_CreateThread(
+ PR_USER_THREAD,
+ shared?SharedCondVarThread:PrivateCondVarThread,
+ info,
+ PR_PRIORITY_NORMAL,
+ scope,
+ PR_JOINABLE_THREAD,
+ 0);
+ if (!info->thread) {
+ PL_PrintError("error creating thread\n");
+ }
+}
+
+
+void
+CondVarTestSUU(void *_arg)
+{
+ PRInt32 arg = (PRInt32)_arg;
+ PRInt32 index, loops;
+ threadinfo *list;
+ PRLock *sharedlock;
+ PRCondVar *sharedcvar;
+ PRLock *exitlock;
+ PRCondVar *exitcvar;
+
+ exitcount=0;
+ tcount=0;
+ list = (threadinfo *)PR_MALLOC(sizeof(threadinfo) * (arg * 4));
+
+ sharedlock = PR_NewLock();
+ sharedcvar = PR_NewCondVar(sharedlock);
+ exitlock = PR_NewLock();
+ exitcvar = PR_NewCondVar(exitlock);
+
+ /* Create the threads */
+ for(index=0; index<arg; ) {
+ CreateTestThread(&list[index],
+ index,
+ sharedlock,
+ sharedcvar,
+ count,
+ PR_INTERVAL_NO_TIMEOUT,
+ &tcount,
+ exitlock,
+ exitcvar,
+ &exitcount,
+ PR_TRUE,
+ PR_LOCAL_THREAD);
+ index++;
+ DPRINTF(("CondVarTestSUU: created thread 0x%lx\n",list[index].thread));
+ }
+
+ for (loops = 0; loops < count; loops++) {
+ /* Notify the threads */
+ for(index=0; index<(arg); index++) {
+ PR_Lock(list[index].lock);
+ (*list[index].tcount)++;
+ PR_NotifyCondVar(list[index].cvar);
+ PR_Unlock(list[index].lock);
+ DPRINTF(("PrivateCondVarThread: thread 0x%lx notified cvar = 0x%lx\n",
+ PR_GetCurrentThread(), list[index].cvar));
+ }
+
+ /* Wait for threads to finish */
+ PR_Lock(exitlock);
+ while(exitcount < arg) {
+ PR_WaitCondVar(exitcvar, PR_SecondsToInterval(60));
+ }
+ PR_ASSERT(exitcount >= arg);
+ exitcount -= arg;
+ PR_Unlock(exitlock);
+ }
+
+ /* Join all the threads */
+ for(index=0; index<(arg); index++) {
+ PR_JoinThread(list[index].thread);
+ }
+
+ PR_DestroyCondVar(sharedcvar);
+ PR_DestroyLock(sharedlock);
+ PR_DestroyCondVar(exitcvar);
+ PR_DestroyLock(exitlock);
+
+ PR_DELETE(list);
+}
+
+void
+CondVarTestSUK(void *_arg)
+{
+ PRInt32 arg = (PRInt32)_arg;
+ PRInt32 index, loops;
+ threadinfo *list;
+ PRLock *sharedlock;
+ PRCondVar *sharedcvar;
+ PRLock *exitlock;
+ PRCondVar *exitcvar;
+ exitcount=0;
+ tcount=0;
+
+ list = (threadinfo *)PR_MALLOC(sizeof(threadinfo) * (arg * 4));
+
+ sharedlock = PR_NewLock();
+ sharedcvar = PR_NewCondVar(sharedlock);
+ exitlock = PR_NewLock();
+ exitcvar = PR_NewCondVar(exitlock);
+
+ /* Create the threads */
+ for(index=0; index<arg; ) {
+ CreateTestThread(&list[index],
+ index,
+ sharedlock,
+ sharedcvar,
+ count,
+ PR_INTERVAL_NO_TIMEOUT,
+ &tcount,
+ exitlock,
+ exitcvar,
+ &exitcount,
+ PR_TRUE,
+ PR_GLOBAL_THREAD);
+ index++;
+ }
+
+ for (loops = 0; loops < count; loops++) {
+ /* Notify the threads */
+ for(index=0; index<(arg); index++) {
+
+ PR_Lock(list[index].lock);
+ (*list[index].tcount)++;
+ PR_NotifyCondVar(list[index].cvar);
+ PR_Unlock(list[index].lock);
+ }
+
+#if 0
+ printf("wait for threads to be done\n");
+#endif
+ /* Wait for threads to finish */
+ PR_Lock(exitlock);
+ while(exitcount < arg) {
+ PR_WaitCondVar(exitcvar, PR_SecondsToInterval(60));
+ }
+ PR_ASSERT(exitcount >= arg);
+ exitcount -= arg;
+ PR_Unlock(exitlock);
+#if 0
+ printf("threads ready\n");
+#endif
+ }
+
+ /* Join all the threads */
+ for(index=0; index<(arg); index++) {
+ PR_JoinThread(list[index].thread);
+ }
+
+ PR_DestroyCondVar(sharedcvar);
+ PR_DestroyLock(sharedlock);
+ PR_DestroyCondVar(exitcvar);
+ PR_DestroyLock(exitlock);
+
+ PR_DELETE(list);
+}
+
+void
+CondVarTestPUU(void *_arg)
+{
+ PRInt32 arg = (PRInt32)_arg;
+ PRInt32 index, loops;
+ threadinfo *list;
+ PRLock *sharedlock;
+ PRCondVar *sharedcvar;
+ PRLock *exitlock;
+ PRCondVar *exitcvar;
+ PRInt32 *tcount, *saved_tcount;
+
+ exitcount=0;
+ list = (threadinfo *)PR_MALLOC(sizeof(threadinfo) * (arg * 4));
+ saved_tcount = tcount = (PRInt32 *)PR_CALLOC(sizeof(*tcount) * (arg * 4));
+
+ sharedlock = PR_NewLock();
+ sharedcvar = PR_NewCondVar(sharedlock);
+ exitlock = PR_NewLock();
+ exitcvar = PR_NewCondVar(exitlock);
+
+ /* Create the threads */
+ for(index=0; index<arg; ) {
+ list[index].lock = PR_NewLock();
+ list[index].cvar = PR_NewCondVar(list[index].lock);
+ CreateTestThread(&list[index],
+ index,
+ list[index].lock,
+ list[index].cvar,
+ count,
+ PR_INTERVAL_NO_TIMEOUT,
+ tcount,
+ exitlock,
+ exitcvar,
+ &exitcount,
+ PR_FALSE,
+ PR_LOCAL_THREAD);
+
+ DPRINTF(("CondVarTestPUU: created thread 0x%lx\n",list[index].thread));
+ index++;
+ tcount++;
+ }
+
+ for (loops = 0; loops < count; loops++) {
+ /* Notify the threads */
+ for(index=0; index<(arg); index++) {
+
+ PR_Lock(list[index].lock);
+ (*list[index].tcount)++;
+ PR_NotifyCondVar(list[index].cvar);
+ PR_Unlock(list[index].lock);
+ }
+
+ PR_Lock(exitlock);
+ /* Wait for threads to finish */
+ while(exitcount < arg) {
+ DPRINTF(("CondVarTestPUU: thread 0x%lx waiting on exitcvar = 0x%lx cnt = %ld\n",
+ PR_GetCurrentThread(), exitcvar, exitcount));
+ PR_WaitCondVar(exitcvar, PR_SecondsToInterval(60));
+ }
+ PR_ASSERT(exitcount >= arg);
+ exitcount -= arg;
+ PR_Unlock(exitlock);
+ }
+
+ /* Join all the threads */
+ for(index=0; index<(arg); index++) {
+ DPRINTF(("CondVarTestPUU: joining thread 0x%lx\n",list[index].thread));
+ PR_JoinThread(list[index].thread);
+ if (list[index].internal) {
+ PR_Lock(list[index].lock);
+ PR_DestroyCondVar(list[index].cvar);
+ PR_Unlock(list[index].lock);
+ PR_DestroyLock(list[index].lock);
+ }
+ }
+
+ PR_DestroyCondVar(sharedcvar);
+ PR_DestroyLock(sharedlock);
+ PR_DestroyCondVar(exitcvar);
+ PR_DestroyLock(exitlock);
+
+ PR_DELETE(list);
+ PR_DELETE(saved_tcount);
+}
+
+void
+CondVarTestPUK(void *_arg)
+{
+ PRInt32 arg = (PRInt32)_arg;
+ PRInt32 index, loops;
+ threadinfo *list;
+ PRLock *sharedlock;
+ PRCondVar *sharedcvar;
+ PRLock *exitlock;
+ PRCondVar *exitcvar;
+ PRInt32 *tcount, *saved_tcount;
+
+ exitcount=0;
+ list = (threadinfo *)PR_MALLOC(sizeof(threadinfo) * (arg * 4));
+ saved_tcount = tcount = (PRInt32 *)PR_CALLOC(sizeof(*tcount) * (arg * 4));
+
+ sharedlock = PR_NewLock();
+ sharedcvar = PR_NewCondVar(sharedlock);
+ exitlock = PR_NewLock();
+ exitcvar = PR_NewCondVar(exitlock);
+
+ /* Create the threads */
+ for(index=0; index<arg; ) {
+ list[index].lock = PR_NewLock();
+ list[index].cvar = PR_NewCondVar(list[index].lock);
+ CreateTestThread(&list[index],
+ index,
+ list[index].lock,
+ list[index].cvar,
+ count,
+ PR_INTERVAL_NO_TIMEOUT,
+ tcount,
+ exitlock,
+ exitcvar,
+ &exitcount,
+ PR_FALSE,
+ PR_GLOBAL_THREAD);
+
+ index++;
+ tcount++;
+ }
+
+ for (loops = 0; loops < count; loops++) {
+ /* Notify the threads */
+ for(index=0; index<(arg); index++) {
+
+ PR_Lock(list[index].lock);
+ (*list[index].tcount)++;
+ PR_NotifyCondVar(list[index].cvar);
+ PR_Unlock(list[index].lock);
+ }
+
+ /* Wait for threads to finish */
+ PR_Lock(exitlock);
+ while(exitcount < arg) {
+ PR_WaitCondVar(exitcvar, PR_SecondsToInterval(60));
+ }
+ PR_ASSERT(exitcount >= arg);
+ exitcount -= arg;
+ PR_Unlock(exitlock);
+ }
+
+ /* Join all the threads */
+ for(index=0; index<(arg); index++) {
+ PR_JoinThread(list[index].thread);
+ if (list[index].internal) {
+ PR_Lock(list[index].lock);
+ PR_DestroyCondVar(list[index].cvar);
+ PR_Unlock(list[index].lock);
+ PR_DestroyLock(list[index].lock);
+ }
+ }
+
+ PR_DestroyCondVar(sharedcvar);
+ PR_DestroyLock(sharedlock);
+ PR_DestroyCondVar(exitcvar);
+ PR_DestroyLock(exitlock);
+
+ PR_DELETE(list);
+ PR_DELETE(saved_tcount);
+}
+
+void
+CondVarTest(void *_arg)
+{
+ PRInt32 arg = (PRInt32)_arg;
+ PRInt32 index, loops;
+ threadinfo *list;
+ PRLock *sharedlock;
+ PRCondVar *sharedcvar;
+ PRLock *exitlock;
+ PRCondVar *exitcvar;
+ PRInt32 *ptcount, *saved_ptcount;
+
+ exitcount=0;
+ tcount=0;
+ list = (threadinfo *)PR_MALLOC(sizeof(threadinfo) * (arg * 4));
+ saved_ptcount = ptcount = (PRInt32 *)PR_CALLOC(sizeof(*ptcount) * (arg * 4));
+
+ sharedlock = PR_NewLock();
+ sharedcvar = PR_NewCondVar(sharedlock);
+ exitlock = PR_NewLock();
+ exitcvar = PR_NewCondVar(exitlock);
+
+ /* Create the threads */
+ for(index=0; index<arg*4; ) {
+ CreateTestThread(&list[index],
+ index,
+ sharedlock,
+ sharedcvar,
+ count,
+ PR_INTERVAL_NO_TIMEOUT,
+ &tcount,
+ exitlock,
+ exitcvar,
+ &exitcount,
+ PR_TRUE,
+ PR_LOCAL_THREAD);
+
+ index++;
+ CreateTestThread(&list[index],
+ index,
+ sharedlock,
+ sharedcvar,
+ count,
+ PR_INTERVAL_NO_TIMEOUT,
+ &tcount,
+ exitlock,
+ exitcvar,
+ &exitcount,
+ PR_TRUE,
+ PR_GLOBAL_THREAD);
+
+ index++;
+ list[index].lock = PR_NewLock();
+ list[index].cvar = PR_NewCondVar(list[index].lock);
+ CreateTestThread(&list[index],
+ index,
+ list[index].lock,
+ list[index].cvar,
+ count,
+ PR_INTERVAL_NO_TIMEOUT,
+ ptcount,
+ exitlock,
+ exitcvar,
+ &exitcount,
+ PR_FALSE,
+ PR_LOCAL_THREAD);
+ index++;
+ ptcount++;
+ list[index].lock = PR_NewLock();
+ list[index].cvar = PR_NewCondVar(list[index].lock);
+ CreateTestThread(&list[index],
+ index,
+ list[index].lock,
+ list[index].cvar,
+ count,
+ PR_INTERVAL_NO_TIMEOUT,
+ ptcount,
+ exitlock,
+ exitcvar,
+ &exitcount,
+ PR_FALSE,
+ PR_GLOBAL_THREAD);
+
+ index++;
+ ptcount++;
+ }
+
+ for (loops = 0; loops < count; loops++) {
+
+ /* Notify the threads */
+ for(index=0; index<(arg*4); index++) {
+ PR_Lock(list[index].lock);
+ (*list[index].tcount)++;
+ PR_NotifyCondVar(list[index].cvar);
+ PR_Unlock(list[index].lock);
+ }
+
+#if 0
+ printf("wait for threads done\n");
+#endif
+
+ /* Wait for threads to finish */
+ PR_Lock(exitlock);
+ while(exitcount < arg*4) {
+ PR_WaitCondVar(exitcvar, PR_SecondsToInterval(60));
+ }
+ PR_ASSERT(exitcount >= arg*4);
+ exitcount -= arg*4;
+ PR_Unlock(exitlock);
+#if 0
+ printf("threads ready\n");
+#endif
+ }
+
+ /* Join all the threads */
+ for(index=0; index<(arg*4); index++) {
+ PR_JoinThread(list[index].thread);
+ if (list[index].internal) {
+ PR_Lock(list[index].lock);
+ PR_DestroyCondVar(list[index].cvar);
+ PR_Unlock(list[index].lock);
+ PR_DestroyLock(list[index].lock);
+ }
+ }
+
+ PR_DestroyCondVar(sharedcvar);
+ PR_DestroyLock(sharedlock);
+ PR_DestroyCondVar(exitcvar);
+ PR_DestroyLock(exitlock);
+
+ PR_DELETE(list);
+ PR_DELETE(saved_ptcount);
+}
+
+void
+CondVarTimeoutTest(void *_arg)
+{
+ PRInt32 arg = (PRInt32)_arg;
+ PRInt32 index, loops;
+ threadinfo *list;
+ PRLock *sharedlock;
+ PRCondVar *sharedcvar;
+ PRLock *exitlock;
+ PRCondVar *exitcvar;
+
+ list = (threadinfo *)PR_MALLOC(sizeof(threadinfo) * (arg * 4));
+
+ sharedlock = PR_NewLock();
+ sharedcvar = PR_NewCondVar(sharedlock);
+ exitlock = PR_NewLock();
+ exitcvar = PR_NewCondVar(exitlock);
+
+ /* Create the threads */
+ for(index=0; index<arg*4; ) {
+ CreateTestThread(&list[index],
+ index,
+ sharedlock,
+ sharedcvar,
+ count,
+ PR_MillisecondsToInterval(50),
+ &tcount,
+ exitlock,
+ exitcvar,
+ &exitcount,
+ PR_TRUE,
+ PR_LOCAL_THREAD);
+ index++;
+ CreateTestThread(&list[index],
+ index,
+ sharedlock,
+ sharedcvar,
+ count,
+ PR_MillisecondsToInterval(50),
+ &tcount,
+ exitlock,
+ exitcvar,
+ &exitcount,
+ PR_TRUE,
+ PR_GLOBAL_THREAD);
+ index++;
+ list[index].lock = PR_NewLock();
+ list[index].cvar = PR_NewCondVar(list[index].lock);
+ CreateTestThread(&list[index],
+ index,
+ list[index].lock,
+ list[index].cvar,
+ count,
+ PR_MillisecondsToInterval(50),
+ &tcount,
+ exitlock,
+ exitcvar,
+ &exitcount,
+ PR_FALSE,
+ PR_LOCAL_THREAD);
+ index++;
+
+ list[index].lock = PR_NewLock();
+ list[index].cvar = PR_NewCondVar(list[index].lock);
+ CreateTestThread(&list[index],
+ index,
+ list[index].lock,
+ list[index].cvar,
+ count,
+ PR_MillisecondsToInterval(50),
+ &tcount,
+ exitlock,
+ exitcvar,
+ &exitcount,
+ PR_FALSE,
+ PR_GLOBAL_THREAD);
+
+ index++;
+ }
+
+ for (loops = 0; loops < count; loops++) {
+
+ /* Wait for threads to finish */
+ PR_Lock(exitlock);
+ while(exitcount < arg*4) {
+ PR_WaitCondVar(exitcvar, PR_SecondsToInterval(60));
+ }
+ PR_ASSERT(exitcount >= arg*4);
+ exitcount -= arg*4;
+ PR_Unlock(exitlock);
+ }
+
+
+ /* Join all the threads */
+ for(index=0; index<(arg*4); index++) {
+ PR_JoinThread(list[index].thread);
+ if (list[index].internal) {
+ PR_Lock(list[index].lock);
+ PR_DestroyCondVar(list[index].cvar);
+ PR_Unlock(list[index].lock);
+ PR_DestroyLock(list[index].lock);
+ }
+ }
+
+ PR_DestroyCondVar(sharedcvar);
+ PR_DestroyLock(sharedlock);
+ PR_DestroyCondVar(exitcvar);
+ PR_DestroyLock(exitlock);
+
+ PR_DELETE(list);
+}
+
+void
+CondVarMixedTest(void *_arg)
+{
+ PRInt32 arg = (PRInt32)_arg;
+ PRInt32 index, loops;
+ threadinfo *list;
+ PRLock *sharedlock;
+ PRCondVar *sharedcvar;
+ PRLock *exitlock;
+ PRCondVar *exitcvar;
+ PRInt32 *ptcount;
+
+ exitcount=0;
+ tcount=0;
+ list = (threadinfo *)PR_MALLOC(sizeof(threadinfo) * (arg * 4));
+ ptcount = (PRInt32 *)PR_CALLOC(sizeof(*ptcount) * (arg * 4));
+
+ sharedlock = PR_NewLock();
+ sharedcvar = PR_NewCondVar(sharedlock);
+ exitlock = PR_NewLock();
+ exitcvar = PR_NewCondVar(exitlock);
+
+ /* Create the threads */
+ for(index=0; index<arg*4; ) {
+ CreateTestThread(&list[index],
+ index,
+ sharedlock,
+ sharedcvar,
+ count,
+ PR_MillisecondsToInterval(50),
+ &tcount,
+ exitlock,
+ exitcvar,
+ &exitcount,
+ PR_TRUE,
+ PR_LOCAL_THREAD);
+ index++;
+ CreateTestThread(&list[index],
+ index,
+ sharedlock,
+ sharedcvar,
+ count,
+ PR_MillisecondsToInterval(50),
+ &tcount,
+ exitlock,
+ exitcvar,
+ &exitcount,
+ PR_TRUE,
+ PR_GLOBAL_THREAD);
+ index++;
+ list[index].lock = PR_NewLock();
+ list[index].cvar = PR_NewCondVar(list[index].lock);
+ CreateTestThread(&list[index],
+ index,
+ list[index].lock,
+ list[index].cvar,
+ count,
+ PR_MillisecondsToInterval(50),
+ ptcount,
+ exitlock,
+ exitcvar,
+ &exitcount,
+ PR_FALSE,
+ PR_LOCAL_THREAD);
+ index++;
+ ptcount++;
+
+ list[index].lock = PR_NewLock();
+ list[index].cvar = PR_NewCondVar(list[index].lock);
+ CreateTestThread(&list[index],
+ index,
+ list[index].lock,
+ list[index].cvar,
+ count,
+ PR_MillisecondsToInterval(50),
+ ptcount,
+ exitlock,
+ exitcvar,
+ &exitcount,
+ PR_FALSE,
+ PR_GLOBAL_THREAD);
+ index++;
+ ptcount++;
+ }
+
+
+ /* Notify every 3rd thread */
+ for (loops = 0; loops < count; loops++) {
+
+ /* Notify the threads */
+ for(index=0; index<(arg*4); index+=3) {
+
+ PR_Lock(list[index].lock);
+ *list[index].tcount++;
+ PR_NotifyCondVar(list[index].cvar);
+ PR_Unlock(list[index].lock);
+
+ }
+ /* Wait for threads to finish */
+ PR_Lock(exitlock);
+ while(exitcount < arg*4) {
+ PR_WaitCondVar(exitcvar, PR_SecondsToInterval(60));
+ }
+ PR_ASSERT(exitcount >= arg*4);
+ exitcount -= arg*4;
+ PR_Unlock(exitlock);
+ }
+
+ /* Join all the threads */
+ for(index=0; index<(arg*4); index++) {
+ PR_JoinThread(list[index].thread);
+ if (list[index].internal) {
+ PR_Lock(list[index].lock);
+ PR_DestroyCondVar(list[index].cvar);
+ PR_Unlock(list[index].lock);
+ PR_DestroyLock(list[index].lock);
+ }
+ }
+
+ PR_DestroyCondVar(sharedcvar);
+ PR_DestroyLock(sharedlock);
+
+ PR_DELETE(list);
+}
+
+void
+CondVarCombinedTest(void *arg)
+{
+ PRThread *threads[3];
+
+ threads[0] = PR_CreateThread(PR_USER_THREAD,
+ CondVarTest,
+ (void *)arg,
+ PR_PRIORITY_NORMAL,
+ PR_GLOBAL_THREAD,
+ PR_JOINABLE_THREAD,
+ 0);
+ threads[1] = PR_CreateThread(PR_USER_THREAD,
+ CondVarTimeoutTest,
+ (void *)arg,
+ PR_PRIORITY_NORMAL,
+ PR_GLOBAL_THREAD,
+ PR_JOINABLE_THREAD,
+ 0);
+ threads[2] = PR_CreateThread(PR_USER_THREAD,
+ CondVarMixedTest,
+ (void *)arg,
+ PR_PRIORITY_NORMAL,
+ PR_GLOBAL_THREAD,
+ PR_JOINABLE_THREAD,
+ 0);
+
+ PR_JoinThread(threads[0]);
+ PR_JoinThread(threads[1]);
+ PR_JoinThread(threads[2]);
+}
+
+/************************************************************************/
+
+static void Measure(void (*func)(void *), PRInt32 arg, const char *msg)
+{
+ PRIntervalTime start, stop;
+ double d;
+
+ start = PR_IntervalNow();
+ (*func)((void *)arg);
+ stop = PR_IntervalNow();
+
+ d = (double)PR_IntervalToMicroseconds(stop - start);
+
+ printf("%40s: %6.2f usec\n", msg, d / count);
+}
+
+static PRIntn PR_CALLBACK RealMain(int argc, char **argv)
+{
+ PRInt32 threads, default_threads = DEFAULT_THREADS;
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "vc:t:");
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 'v': /* debug mode */
+ _debug_on = 1;
+ break;
+ case 'c': /* loop counter */
+ count = atoi(opt->value);
+ break;
+ case 't': /* number of threads involved */
+ default_threads = atoi(opt->value);
+ break;
+ default:
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ if (0 == count) {
+ count = DEFAULT_COUNT;
+ }
+ if (0 == default_threads) {
+ default_threads = DEFAULT_THREADS;
+ }
+
+ printf("\n\
+CondVar Test: \n\
+ \n\
+Simple test creates several local and global threads; half use a single,\n\
+shared condvar, and the other half have their own condvar. The main \n\
+thread then loops notifying them to wakeup. \n\
+ \n\
+The timeout test is very similar except that the threads are not \n\
+notified. They will all wakeup on a 1 second timeout. \n\
+ \n\
+The mixed test combines the simple test and the timeout test; every \n\
+third thread is notified, the other threads are expected to timeout \n\
+correctly. \n\
+ \n\
+Lastly, the combined test creates a thread for each of the above three \n\
+cases and they all run simultaneously. \n\
+ \n\
+This test is run with %d, %d, %d, and %d threads of each type.\n\n",
+ default_threads, default_threads*2, default_threads*3, default_threads*4);
+
+ PR_SetConcurrency(2);
+
+ for (threads = default_threads; threads < default_threads*5; threads+=default_threads) {
+ printf("\n%ld Thread tests\n", threads);
+ Measure(CondVarTestSUU, threads, "Condvar simple test shared UU");
+ Measure(CondVarTestSUK, threads, "Condvar simple test shared UK");
+ Measure(CondVarTestPUU, threads, "Condvar simple test priv UU");
+ Measure(CondVarTestPUK, threads, "Condvar simple test priv UK");
+ Measure(CondVarTest, threads, "Condvar simple test All");
+ Measure(CondVarTimeoutTest, threads, "Condvar timeout test");
+#if 0
+ Measure(CondVarMixedTest, threads, "Condvar mixed timeout test");
+ Measure(CondVarCombinedTest, threads, "Combined condvar test");
+#endif
+ }
+
+ printf("PASS\n");
+
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ PRIntn rv;
+
+ PR_STDIO_INIT();
+ rv = PR_Initialize(RealMain, argc, argv, 0);
+ return rv;
+} /* main */
diff --git a/nsprpub/pr/tests/dbmalloc.c b/nsprpub/pr/tests/dbmalloc.c
new file mode 100644
index 0000000000..2a7ad4fa85
--- /dev/null
+++ b/nsprpub/pr/tests/dbmalloc.c
@@ -0,0 +1,339 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/***********************************************************************
+**
+** Name: dbmalloc.c
+**
+** Description: Testing malloc (OBSOLETE)
+**
+** Modification History:
+** 14-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
+** The debug mode will print all of the printfs associated with this test.
+** The regress mode will be the default mode. Since the regress tool limits
+** the output to a one line status:PASS or FAIL,all of the printf statements
+** have been handled with an if (debug_mode) statement.
+***********************************************************************/
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <string.h>
+#include "nspr.h"
+
+void
+usage
+(
+ void
+)
+{
+ fprintf(stderr, "Usage: dbmalloc ('-m'|'-s') '-f' num_fails ('-d'|'-n') filename [...]\n");
+ exit(0);
+}
+
+typedef struct node_struct
+{
+ struct node_struct *next, *prev;
+ int line;
+ char value[4];
+}
+node_t,
+*node_pt;
+
+node_pt get_node(const char *line)
+{
+ node_pt rv;
+ int l = strlen(line);
+ rv = (node_pt)PR_MALLOC(sizeof(node_t) + l + 1 - 4);
+ if( (node_pt)0 == rv ) {
+ return (node_pt)0;
+ }
+ memcpy(&rv->value[0], line, l+1);
+ rv->next = rv->prev = (node_pt)0;
+ return rv;
+}
+
+void
+dump
+(
+ const char *name,
+ node_pt node,
+ int mf,
+ int debug
+)
+{
+ if( (node_pt)0 != node->prev ) {
+ dump(name, node->prev, mf, debug);
+ }
+ if( 0 != debug ) {
+ printf("[%s]: %6d: %s", name, node->line, node->value);
+ }
+ if( node->line == mf ) {
+ fprintf(stderr, "[%s]: Line %d was allocated!\n", name, node->line);
+ }
+ if( (node_pt)0 != node->next ) {
+ dump(name, node->next, mf, debug);
+ }
+ return;
+}
+
+void
+release
+(
+ node_pt node
+)
+{
+ if( (node_pt)0 != node->prev ) {
+ release(node->prev);
+ }
+ if( (node_pt)0 != node->next ) {
+ release(node->next);
+ }
+ PR_DELETE(node);
+}
+
+int
+t2
+(
+ const char *name,
+ int mf,
+ int debug
+)
+{
+ int rv;
+ FILE *fp;
+ int l = 0;
+ node_pt head = (node_pt)0;
+ char buffer[ BUFSIZ ];
+
+ fp = fopen(name, "r");
+ if( (FILE *)0 == fp )
+ {
+ fprintf(stderr, "[%s]: Cannot open \"%s.\"\n", name, name);
+ return -1;
+ }
+
+ /* fgets mallocs a buffer, first time through. */
+ if( (char *)0 == fgets(buffer, BUFSIZ, fp) )
+ {
+ fprintf(stderr, "[%s]: \"%s\" is empty.\n", name, name);
+ (void)fclose(fp);
+ return -1;
+ }
+
+ rewind(fp);
+
+ if( PR_SUCCESS != PR_ClearMallocCount() )
+ {
+ fprintf(stderr, "[%s]: Cannot clear malloc count.\n", name);
+ (void)fclose(fp);
+ return -1;
+ }
+
+ if( PR_SUCCESS != PR_SetMallocCountdown(mf) )
+ {
+ fprintf(stderr, "[%s]: Cannot set malloc countdown to %d\n", name, mf);
+ (void)fclose(fp);
+ return -1;
+ }
+
+ while( fgets(buffer, BUFSIZ, fp) )
+ {
+ node_pt n;
+ node_pt *w = &head;
+
+ if( (strlen(buffer) == (BUFSIZ-1)) && (buffer[BUFSIZ-2] != '\n') ) {
+ buffer[BUFSIZ-2] == '\n';
+ }
+
+ l++;
+
+ n = get_node(buffer);
+ if( (node_pt)0 == n )
+ {
+ printf("[%s]: Line %d: malloc failure!\n", name, l);
+ continue;
+ }
+
+ n->line = l;
+
+ while( 1 )
+ {
+ int comp;
+
+ if( (node_pt)0 == *w )
+ {
+ *w = n;
+ break;
+ }
+
+ comp = strcmp((*w)->value, n->value);
+ if( comp < 0 ) {
+ w = &(*w)->next;
+ }
+ else {
+ w = &(*w)->prev;
+ }
+ }
+ }
+
+ (void)fclose(fp);
+
+ dump(name, head, mf, debug);
+
+ rv = PR_GetMallocCount();
+ PR_ClearMallocCountdown();
+
+ release(head);
+
+ return rv;
+}
+
+int nf = 0;
+int debug = 0;
+
+void
+test
+(
+ const char *name
+)
+{
+ int n, i;
+
+ extern int nf, debug;
+
+ printf("[%s]: starting test 0\n", name);
+ n = t2(name, 0, debug);
+ if( -1 == n ) {
+ return;
+ }
+ printf("[%s]: test 0 had %ld allocations.\n", name, n);
+
+ if( 0 >= n ) {
+ return;
+ }
+
+ for( i = 0; i < nf; i++ )
+ {
+ int which = rand() % n;
+ if( 0 == which ) {
+ printf("[%s]: starting test %d -- no allocation should fail\n", name, i+1);
+ }
+ else {
+ printf("[%s]: starting test %d -- allocation %d should fail\n", name, i+1, which);
+ }
+ (void)t2(name, which, debug);
+ printf("[%s]: test %d done.\n", name, i+1);
+ }
+
+ return;
+}
+
+int main(int argc, char **argv)
+{
+ int okay = 0;
+ int multithread = 0;
+
+ struct threadlist
+ {
+ struct threadlist *next;
+ PRThread *thread;
+ }
+ *threadhead = (struct threadlist *)0;
+
+ extern int nf, debug;
+
+ srand(time(0));
+
+ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
+ PR_STDIO_INIT();
+
+ printf("[main]: We %s using the debugging malloc.\n",
+ PR_IsDebuggingMalloc() ? "ARE" : "ARE NOT");
+
+ while( argv++, --argc )
+ {
+ if( '-' == argv[0][0] )
+ {
+ switch( argv[0][1] )
+ {
+ case 'f':
+ nf = atoi(argv[0][2] ? &argv[0][2] :
+ --argc ? *++argv : "0");
+ break;
+ case 'd':
+ debug = 1;
+ break;
+ case 'n':
+ debug = 0;
+ break;
+ case 'm':
+ multithread = 1;
+ break;
+ case 's':
+ multithread = 0;
+ break;
+ default:
+ usage();
+ break;
+ }
+ }
+ else
+ {
+ FILE *fp = fopen(*argv, "r");
+ if( (FILE *)0 == fp )
+ {
+ fprintf(stderr, "Cannot open \"%s.\"\n", *argv);
+ continue;
+ }
+
+ okay++;
+ (void)fclose(fp);
+ if( multithread )
+ {
+ struct threadlist *n;
+
+ n = (struct threadlist *)malloc(sizeof(struct threadlist));
+ if( (struct threadlist *)0 == n )
+ {
+ fprintf(stderr, "This is getting tedious. \"%s\"\n", *argv);
+ continue;
+ }
+
+ n->next = threadhead;
+ n->thread = PR_CreateThread(PR_USER_THREAD, (void (*)(void *))test,
+ *argv, PR_PRIORITY_NORMAL,
+ PR_LOCAL_THREAD, PR_JOINABLE_THREAD,
+ 0);
+ if( (PRThread *)0 == n->thread )
+ {
+ fprintf(stderr, "Can't create thread for \"%s.\"\n", *argv);
+ continue;
+ }
+ else
+ {
+ threadhead = n;
+ }
+ }
+ else
+ {
+ test(*argv);
+ }
+ }
+ }
+
+ if( okay == 0 ) {
+ usage();
+ }
+ else while( (struct threadlist *)0 != threadhead )
+ {
+ struct threadlist *x = threadhead->next;
+ (void)PR_JoinThread(threadhead->thread);
+ PR_DELETE(threadhead);
+ threadhead = x;
+ }
+
+ return 0;
+}
+
diff --git a/nsprpub/pr/tests/dbmalloc1.c b/nsprpub/pr/tests/dbmalloc1.c
new file mode 100644
index 0000000000..a7e995c409
--- /dev/null
+++ b/nsprpub/pr/tests/dbmalloc1.c
@@ -0,0 +1,114 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/***********************************************************************
+**
+** Name: dbmalloc1.c (OBSOLETE)
+**
+** Description: Tests PR_SetMallocCountdown PR_ClearMallocCountdown functions.
+**
+** Modification History:
+** 14-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
+** The debug mode will print all of the printfs associated with this test.
+** The regress mode will be the default mode. Since the regress tool limits
+** the output to a one line status:PASS or FAIL,all of the printf statements
+** have been handled with an if (debug_mode) statement.
+** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to
+** recognize the return code from tha main program.
+**
+** 12-June-97 AGarcia Revert to return code 0 and 1, remove debug option (obsolete).
+***********************************************************************/
+
+
+/***********************************************************************
+** Includes
+***********************************************************************/
+#include <stdio.h>
+#include <stdlib.h>
+#include "nspr.h"
+
+PRIntn failed_already=0;
+PRIntn debug_mode;
+
+/* variable used for both r1 and r2 tests */
+int should_fail =0;
+int actually_failed=0;
+
+
+void
+r1
+(
+ void
+)
+{
+ int i;
+ actually_failed=0;
+ for( i = 0; i < 5; i++ )
+ {
+ void *x = PR_MALLOC(128);
+ if( (void *)0 == x ) {
+ if (debug_mode) {
+ printf("\tMalloc %d failed.\n", i+1);
+ }
+ actually_failed = 1;
+ }
+ PR_DELETE(x);
+ }
+
+ if (((should_fail != actually_failed) & (!debug_mode))) {
+ failed_already=1;
+ }
+
+
+ return;
+}
+
+void
+r2
+(
+ void
+)
+{
+ int i;
+
+ for( i = 0; i <= 5; i++ )
+ {
+ should_fail =0;
+ if( 0 == i ) {
+ if (debug_mode) {
+ printf("No malloc should fail:\n");
+ }
+ }
+ else {
+ if (debug_mode) {
+ printf("Malloc %d should fail:\n", i);
+ }
+ should_fail = 1;
+ }
+ PR_SetMallocCountdown(i);
+ r1();
+ PR_ClearMallocCountdown();
+ }
+}
+
+int main(int argc, char **argv)
+{
+
+ /* main test */
+
+ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
+ PR_STDIO_INIT();
+ r2();
+
+ if(failed_already) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+
+
+}
+
diff --git a/nsprpub/pr/tests/dceemu.c b/nsprpub/pr/tests/dceemu.c
new file mode 100644
index 0000000000..2b1d0901a9
--- /dev/null
+++ b/nsprpub/pr/tests/dceemu.c
@@ -0,0 +1,109 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+** File: dceemu.c
+** Description: testing the DCE emulation api
+**
+** Modification History:
+** 14-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
+** The debug mode will print all of the printfs associated with this test.
+** The regress mode will be the default mode. Since the regress tool limits
+** the output to a one line status:PASS or FAIL,all of the printf statements
+** have been handled with an if (debug_mode) statement.
+** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to
+** recognize the return code from tha main program.
+** 12-June-97 Revert to return code 0 and 1, remove debug option (obsolete).
+**/
+
+/***********************************************************************
+** Includes
+***********************************************************************/
+
+#include "prlog.h"
+#include "prinit.h"
+#include "prpdce.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+PRIntn failed_already=0;
+PRIntn debug_mode=0;
+
+static PRIntn prmain(PRIntn argc, char **argv)
+{
+ PRStatus rv;
+ PRLock *ml = PR_NewLock();
+ PRCondVar *cv = PRP_NewNakedCondVar();
+ PRIntervalTime tenmsecs = PR_MillisecondsToInterval(10);
+
+ rv = PRP_TryLock(ml);
+ PR_ASSERT(PR_SUCCESS == rv);
+ if ((rv != PR_SUCCESS) & (!debug_mode)) {
+ failed_already=1;
+ }
+
+ rv = PRP_TryLock(ml);
+ PR_ASSERT(PR_FAILURE == rv);
+ if ((rv != PR_FAILURE) & (!debug_mode)) {
+ failed_already=1;
+ }
+
+ rv = PRP_NakedNotify(cv);
+ PR_ASSERT(PR_SUCCESS == rv);
+ if ((rv != PR_SUCCESS) & (!debug_mode)) {
+ failed_already=1;
+ }
+
+ rv = PRP_NakedBroadcast(cv);
+ PR_ASSERT(PR_SUCCESS == rv);
+ if ((rv != PR_SUCCESS) & (!debug_mode)) {
+ failed_already=1;
+ }
+
+ rv = PRP_NakedWait(cv, ml, tenmsecs);
+ PR_ASSERT(PR_SUCCESS == rv);
+ if ((rv != PR_SUCCESS) & (!debug_mode)) {
+ failed_already=1;
+ }
+
+ PR_Unlock(ml);
+
+ rv = PRP_NakedNotify(cv);
+ PR_ASSERT(PR_SUCCESS == rv);
+ if ((rv != PR_SUCCESS) & (!debug_mode)) {
+ failed_already=1;
+ }
+
+ rv = PRP_NakedBroadcast(cv);
+ PR_ASSERT(PR_SUCCESS == rv);
+ if ((rv != PR_SUCCESS) & (!debug_mode)) {
+ failed_already=1;
+ }
+
+ PRP_DestroyNakedCondVar(cv);
+ PR_DestroyLock(ml);
+
+ if (debug_mode) {
+ printf("Test succeeded\n");
+ }
+
+ return 0;
+
+} /* prmain */
+
+int main(int argc, char **argv)
+{
+ PR_Initialize(prmain, argc, argv, 0);
+ if(failed_already) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+} /* main */
+
+
+/* decemu.c */
diff --git a/nsprpub/pr/tests/depend.c b/nsprpub/pr/tests/depend.c
new file mode 100644
index 0000000000..f3689bc460
--- /dev/null
+++ b/nsprpub/pr/tests/depend.c
@@ -0,0 +1,132 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/***********************************************************************
+** 1996 - Netscape Communications Corporation
+**
+**
+** Name: depend.c
+** Description: Test to enumerate the dependencies
+*
+** Modification History:
+** 14-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
+** The debug mode will print all of the printfs associated with this test.
+** The regress mode will be the default mode. Since the regress tool limits
+** the output to a one line status:PASS or FAIL,all of the printf statements
+** have been handled with an if (debug_mode) statement.
+***********************************************************************/
+#include "prinit.h"
+
+/***********************************************************************
+** Includes
+***********************************************************************/
+/* Used to get the command line option */
+#include "plgetopt.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+static void PrintVersion(
+ const char *msg, const PRVersion* info, PRIntn tab)
+{
+ static const len = 20;
+ static const char *tabs = {" "};
+
+ tab *= 2;
+ if (tab > len) {
+ tab = len;
+ }
+ printf("%s", &tabs[len - tab]);
+ printf("%s ", msg);
+ printf("%s ", info->id);
+ printf("%d.%d", info->major, info->minor);
+ if (0 != info->patch) {
+ printf(".p%d", info->patch);
+ }
+ printf("\n");
+} /* PrintDependency */
+
+static void ChaseDependents(const PRVersionInfo *info, PRIntn tab)
+{
+ PrintVersion("exports", &info->selfExport, tab);
+ if (NULL != info->importEnumerator)
+ {
+ const PRDependencyInfo *dependent = NULL;
+ while (NULL != (dependent = info->importEnumerator(dependent)))
+ {
+ const PRVersionInfo *import = dependent->exportInfoFn();
+ PrintVersion("imports", &dependent->importNeeded, tab);
+ ChaseDependents(import, tab + 1);
+ }
+ }
+} /* ChaseDependents */
+
+static PRVersionInfo hack_export;
+static PRVersionInfo dummy_export;
+static PRDependencyInfo dummy_imports[2];
+
+static const PRVersionInfo *HackExportInfo(void)
+{
+ hack_export.selfExport.major = 11;
+ hack_export.selfExport.minor = 10;
+ hack_export.selfExport.patch = 200;
+ hack_export.selfExport.id = "Hack";
+ hack_export.importEnumerator = NULL;
+ return &hack_export;
+}
+
+static const PRDependencyInfo *DummyImports(
+ const PRDependencyInfo *previous)
+{
+ if (NULL == previous) {
+ return &dummy_imports[0];
+ }
+ else if (&dummy_imports[0] == previous) {
+ return &dummy_imports[1];
+ }
+ else if (&dummy_imports[1] == previous) {
+ return NULL;
+ }
+} /* DummyImports */
+
+static const PRVersionInfo *DummyLibVersion(void)
+{
+ dummy_export.selfExport.major = 1;
+ dummy_export.selfExport.minor = 0;
+ dummy_export.selfExport.patch = 0;
+ dummy_export.selfExport.id = "Dumbass application";
+ dummy_export.importEnumerator = DummyImports;
+
+ dummy_imports[0].importNeeded.major = 2;
+ dummy_imports[0].importNeeded.minor = 0;
+ dummy_imports[0].importNeeded.patch = 0;
+ dummy_imports[0].importNeeded.id = "Netscape Portable Runtime";
+ dummy_imports[0].exportInfoFn = PR_ExportInfo;
+
+ dummy_imports[1].importNeeded.major = 5;
+ dummy_imports[1].importNeeded.minor = 1;
+ dummy_imports[1].importNeeded.patch = 2;
+ dummy_imports[1].importNeeded.id = "Hack Library";
+ dummy_imports[1].exportInfoFn = HackExportInfo;
+
+ return &dummy_export;
+} /* DummyLibVersion */
+
+int main(int argc, char **argv)
+{
+ PRIntn tab = 0;
+ const PRVersionInfo *info = DummyLibVersion();
+ const char *buildDate = __DATE__, *buildTime = __TIME__;
+
+ printf("Depend.c build time is %s %s\n", buildDate, buildTime);
+
+ if (NULL != info) {
+ ChaseDependents(info, tab);
+ }
+
+ return 0;
+} /* main */
+
+/* depend.c */
diff --git a/nsprpub/pr/tests/dll/Makefile.in b/nsprpub/pr/tests/dll/Makefile.in
new file mode 100644
index 0000000000..8b8c5ac20d
--- /dev/null
+++ b/nsprpub/pr/tests/dll/Makefile.in
@@ -0,0 +1,77 @@
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#! gmake
+
+MOD_DEPTH = ../../..
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+include $(MOD_DEPTH)/config/autoconf.mk
+
+include $(topsrcdir)/config/config.mk
+
+CSRCS = mygetval.c mysetval.c
+
+INCLUDES = -I$(dist_includedir)
+
+OBJS = $(OBJDIR)/mygetval.$(OBJ_SUFFIX) \
+ $(OBJDIR)/mysetval.$(OBJ_SUFFIX)
+
+ifeq ($(OS_TARGET), WIN16)
+W16OBJS = $(subst $(space),$(comma)$(space),$(OBJS))
+endif
+
+ifeq ($(OS_ARCH), WINNT)
+ifeq ($(OS_TARGET), WIN16)
+# do nothing
+else
+RES=$(OBJDIR)/my.res
+RESNAME=../../../pr/src/nspr.rc
+endif
+endif
+
+ifeq (,$(filter-out WINNT OS2,$(OS_ARCH)))
+IMPORT_LIBRARY = $(OBJDIR)/my.$(LIB_SUFFIX)
+SHARED_LIBRARY = $(OBJDIR)/my.dll
+ifeq ($(OS_ARCH), OS2)
+MAPFILE = $(OBJDIR)/my.def
+GARBAGE += $(MAPFILE)
+MKSHLIB += $(MAPFILE)
+endif
+TARGETS = $(SHARED_LIBRARY) $(IMPORT_LIBRARY)
+else
+ifdef MKSHLIB
+SHARED_LIBRARY = $(OBJDIR)/libmy.$(DLL_SUFFIX)
+endif
+TARGETS = $(SHARED_LIBRARY)
+endif
+
+#
+# To create a loadable module on Darwin, we must override
+# -dynamiclib with -bundle.
+#
+ifeq ($(OS_ARCH),Darwin)
+DSO_LDOPTS = -bundle
+endif
+
+include $(topsrcdir)/config/rules.mk
+
+ifeq ($(OS_TARGET), WIN16)
+# Note: The Win16 target: my.dll requires these macros
+# to be overridden to build the test .dll
+# default values in win16...mk are for release targets.
+#
+OS_DLL_OPTION = NOCASEEXACT
+OS_LIB_FLAGS = -irn
+endif
+
+ifdef SHARED_LIBRARY
+export:: $(TARGETS)
+
+clean::
+ rm -rf $(TARGETS)
+endif
diff --git a/nsprpub/pr/tests/dll/my.def b/nsprpub/pr/tests/dll/my.def
new file mode 100644
index 0000000000..75b71f5ac1
--- /dev/null
+++ b/nsprpub/pr/tests/dll/my.def
@@ -0,0 +1,26 @@
+;+#
+;+# This Source Code Form is subject to the terms of the Mozilla Public
+;+# License, v. 2.0. If a copy of the MPL was not distributed with this
+;+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+;+#
+;+# OK, this file is meant to support SUN, LINUX, AIX, OS/2 and WINDOWS
+;+# 1. For all unix platforms, the string ";-" means "remove this line"
+;+# 2. For all unix platforms, the string " DATA " will be removed from any
+;+# line on which it occurs.
+;+# 3. Lines containing ";+" will have ";+" removed on SUN and LINUX.
+;+# On AIX, lines containing ";+" will be removed.
+;+# 4. For all unix platforms, the string ";;" will thave the ";;" removed.
+;+# 5. For all unix platforms, after the above processing has taken place,
+;+# all characters after the first ";" on the line will be removed.
+;+# And for AIX, the first ";" will also be removed.
+;+# This file is passed directly to windows. Since ';' is a comment, all UNIX
+;+# directives are hidden behind ";", ";+", and ";-"
+;+#
+;+MY_1.0 {
+;+ global:
+LIBRARY my ;-
+EXPORTS ;-
+ My_GetValue;
+ My_SetValue;
+;+ local: *;
+;+};
diff --git a/nsprpub/pr/tests/dll/mygetval.c b/nsprpub/pr/tests/dll/mygetval.c
new file mode 100644
index 0000000000..7fb7002441
--- /dev/null
+++ b/nsprpub/pr/tests/dll/mygetval.c
@@ -0,0 +1,26 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+
+#if defined(WIN16)
+#include <windows.h>
+#endif
+#include "prtypes.h"
+
+extern PRIntn my_global;
+
+PR_IMPLEMENT(PRIntn) My_GetValue()
+{
+ return my_global;
+}
+
+#if defined(WIN16)
+int CALLBACK LibMain( HINSTANCE hInst, WORD wDataSeg,
+ WORD cbHeapSize, LPSTR lpszCmdLine )
+{
+ return TRUE;
+}
+#endif /* WIN16 */
+
diff --git a/nsprpub/pr/tests/dll/mysetval.c b/nsprpub/pr/tests/dll/mysetval.c
new file mode 100644
index 0000000000..232428adf8
--- /dev/null
+++ b/nsprpub/pr/tests/dll/mysetval.c
@@ -0,0 +1,13 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "prtypes.h"
+
+PRIntn my_global = 0;
+
+PR_IMPLEMENT(void) My_SetValue(PRIntn val)
+{
+ my_global = val;
+}
diff --git a/nsprpub/pr/tests/dlltest.c b/nsprpub/pr/tests/dlltest.c
new file mode 100644
index 0000000000..d687322810
--- /dev/null
+++ b/nsprpub/pr/tests/dlltest.c
@@ -0,0 +1,216 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/***********************************************************************
+**
+** Name: dlltest.c
+**
+** Description: test dll functionality.
+**
+** Modification History:
+** 14-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
+** The debug mode will print all of the printfs associated with this test.
+** The regress mode will be the default mode. Since the regress tool limits
+** the output to a one line status:PASS or FAIL,all of the printf statements
+** have been handled with an if (debug_mode) statement.
+** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to
+** recognize the return code from tha main program.
+** 12-June-97 Revert to return code 0 and 1.
+***********************************************************************/
+
+/***********************************************************************
+** Includes
+***********************************************************************/
+#include "prinit.h"
+#include "prlink.h"
+#include "prmem.h"
+#include "prerror.h"
+
+#include "plstr.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+typedef PRIntn (PR_CALLBACK *GetFcnType)(void);
+typedef void (PR_CALLBACK *SetFcnType)(PRIntn);
+
+PRIntn failed_already=0;
+PRIntn debug_mode;
+
+int main(int argc, char** argv)
+{
+ PRLibrary *lib, *lib2; /* two handles to the same library */
+ GetFcnType getFcn;
+ SetFcnType setFcn;
+ PRIntn value;
+ PRStatus status;
+ char *libName;
+
+ if (argc >= 2 && PL_strcmp(argv[1], "-d") == 0) {
+ debug_mode = 1;
+ }
+
+ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
+ PR_STDIO_INIT();
+
+ /*
+ * Test 1: load the library, look up the symbols, call the functions,
+ * and check the results.
+ */
+
+ libName = PR_GetLibraryName("dll", "my");
+ if (debug_mode) {
+ printf("Loading library %s\n", libName);
+ }
+ lib = PR_LoadLibrary(libName);
+ PR_FreeLibraryName(libName);
+ if (lib == NULL) {
+ PRInt32 textLength = PR_GetErrorTextLength();
+ char *text = (char*)PR_MALLOC(textLength + 1);
+ text[0] = '\0';
+ (void)PR_GetErrorText(text);
+ fprintf(
+ stderr, "PR_LoadLibrary failed (%d, %d, %s)\n",
+ PR_GetError(), PR_GetOSError(), text);
+ if (!debug_mode) {
+ failed_already=1;
+ }
+ }
+ getFcn = (GetFcnType) PR_FindSymbol(lib, "My_GetValue");
+ setFcn = (SetFcnType) PR_FindFunctionSymbol(lib, "My_SetValue");
+ (*setFcn)(888);
+ value = (*getFcn)();
+ if (value != 888) {
+ fprintf(stderr, "Test 1 failed: set value to 888, but got %d\n", value);
+ if (!debug_mode) {
+ failed_already=1;
+ }
+ }
+ if (debug_mode) {
+ printf("Test 1 passed\n");
+ }
+
+ /*
+ * Test 2: get a second handle to the same library (this should increment
+ * the reference count), look up the symbols, call the functions, and
+ * check the results.
+ */
+
+ getFcn = (GetFcnType) PR_FindSymbolAndLibrary("My_GetValue", &lib2);
+ if (NULL == getFcn || lib != lib2) {
+ fprintf(stderr, "Test 2 failed: handles for the same library are not "
+ "equal: handle 1: %p, handle 2: %p\n", lib, lib2);
+ if (!debug_mode) {
+ failed_already=1;
+ }
+ }
+ setFcn = (SetFcnType) PR_FindSymbol(lib2, "My_SetValue");
+ value = (*getFcn)();
+ if (value != 888) {
+ fprintf(stderr, "Test 2 failed: value should be 888, but got %d\n",
+ value);
+ if (!debug_mode) {
+ failed_already=1;
+ }
+ }
+ (*setFcn)(777);
+ value = (*getFcn)();
+ if (value != 777) {
+ fprintf(stderr, "Test 2 failed: set value to 777, but got %d\n", value);
+ if (!debug_mode) {
+ failed_already=1;
+ }
+ goto exit_now;
+ }
+ if (debug_mode) {
+ printf("Test 2 passed\n");
+ }
+
+ /*
+ * Test 3: unload the library. The library should still be accessible
+ * via the second handle. do the same things as above.
+ */
+
+ status = PR_UnloadLibrary(lib);
+ if (PR_FAILURE == status) {
+ fprintf(stderr, "Test 3 failed: cannot unload library: (%d, %d)\n",
+ PR_GetError(), PR_GetOSError());
+ if (!debug_mode) {
+ failed_already=1;
+ }
+ goto exit_now;
+ }
+ getFcn = (GetFcnType) PR_FindFunctionSymbol(lib2, "My_GetValue");
+ setFcn = (SetFcnType) PR_FindSymbol(lib2, "My_SetValue");
+ (*setFcn)(666);
+ value = (*getFcn)();
+ if (value != 666) {
+ fprintf(stderr, "Test 3 failed: set value to 666, but got %d\n", value);
+ if (!debug_mode) {
+ failed_already=1;
+ }
+ goto exit_now;
+ }
+ if (debug_mode) {
+ printf("Test 3 passed\n");
+ }
+
+ /*
+ * Test 4: unload the library, testing the reference count mechanism.
+ */
+
+ status = PR_UnloadLibrary(lib2);
+ if (PR_FAILURE == status) {
+ fprintf(stderr, "Test 4 failed: cannot unload library: (%d, %d)\n",
+ PR_GetError(), PR_GetOSError());
+ if (!debug_mode) {
+ failed_already=1;
+ }
+ goto exit_now;
+ }
+ getFcn = (GetFcnType) PR_FindFunctionSymbolAndLibrary("My_GetValue", &lib2);
+ if (NULL != getFcn) {
+ fprintf(stderr, "Test 4 failed: how can we find a symbol "
+ "in an already unloaded library?\n");
+ if (!debug_mode) {
+ failed_already=1;
+ }
+ goto exit_now;
+ }
+ if (debug_mode) {
+ printf("Test 4 passed\n");
+ }
+
+ /*
+ ** Test 5: LoadStaticLibrary()
+ */
+ {
+ PRStaticLinkTable slt[10];
+ PRLibrary *lib;
+
+ lib = PR_LoadStaticLibrary( "my.dll", slt );
+ if ( lib == NULL )
+ {
+ fprintf(stderr, "Test 5: LoadStatiLibrary() failed\n" );
+ goto exit_now;
+ }
+ if (debug_mode)
+ {
+ printf("Test 5 passed\n");
+ }
+ }
+
+ goto exit_now;
+exit_now:
+ PR_Cleanup();
+
+ if (failed_already) {
+ printf("FAILED\n");
+ return 1;
+ } else {
+ printf("PASSED\n");
+ return 0;
+ }
+}
diff --git a/nsprpub/pr/tests/dtoa.c b/nsprpub/pr/tests/dtoa.c
new file mode 100644
index 0000000000..ef2e4dc4de
--- /dev/null
+++ b/nsprpub/pr/tests/dtoa.c
@@ -0,0 +1,213 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/******************************************************************************
+ *
+ * This file contains a test program for the function conversion functions
+ * for double precision code:
+ * PR_strtod
+ * PR_dtoa
+ * PR_cnvtf
+ *
+ * This file was ns/nspr/tests/dtoa.c, created by rrj on 1996/06/22.
+ *
+ *****************************************************************************/
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <string.h>
+#include <locale.h>
+#include "prprf.h"
+#include "prdtoa.h"
+
+static int failed_already = 0;
+
+int main(int argc, char **argv)
+{
+ double num;
+ double num1;
+ double zero = 0.0;
+ char cnvt[50];
+ char *thousands;
+
+ num = 1e24;
+ num1 = PR_strtod("1e24",NULL);
+ if(num1 != num) {
+ fprintf(stderr,"Failed to convert numeric value %s\n","1e24");
+ failed_already = 1;
+ }
+
+ PR_cnvtf(cnvt,sizeof(cnvt),20,num);
+ if(strcmp("1e+24",cnvt) != 0) {
+ fprintf(stderr,"Failed to convert numeric value %lf %s\n",num,cnvt);
+ failed_already = 1;
+ }
+
+ num = 0.001e7;
+ num1 = PR_strtod("0.001e7",NULL);
+ if(num1 != num) {
+ fprintf(stderr,"Failed to convert numeric value %s\n","0.001e7");
+ failed_already = 1;
+ }
+ PR_cnvtf(cnvt,sizeof(cnvt),20,num);
+ if(strcmp("10000",cnvt) != 0) {
+ fprintf(stderr,"Failed to convert numeric value %lf %s\n",num,cnvt);
+ failed_already = 1;
+ }
+
+ num = 0.0000000000000753;
+ num1 = PR_strtod("0.0000000000000753",NULL);
+ if(num1 != num) {
+ fprintf(stderr,"Failed to convert numeric value %s\n",
+ "0.0000000000000753");
+ failed_already = 1;
+ }
+ PR_cnvtf(cnvt,sizeof(cnvt),20,num);
+ if(strcmp("7.53e-14",cnvt) != 0) {
+ fprintf(stderr,"Failed to convert numeric value %lf %s\n",num,cnvt);
+ failed_already = 1;
+ }
+
+ num = 1.867e73;
+ num1 = PR_strtod("1.867e73",NULL);
+ if(num1 != num) {
+ fprintf(stderr,"Failed to convert numeric value %s\n","1.867e73");
+ failed_already = 1;
+ }
+ PR_cnvtf(cnvt,sizeof(cnvt),20,num);
+ if(strcmp("1.867e+73",cnvt) != 0) {
+ fprintf(stderr,"Failed to convert numeric value %lf %s\n",num,cnvt);
+ failed_already = 1;
+ }
+
+
+ num = -1.867e73;
+ num1 = PR_strtod("-1.867e73",NULL);
+ if(num1 != num) {
+ fprintf(stderr,"Failed to convert numeric value %s\n","-1.867e73");
+ failed_already = 1;
+ }
+ PR_cnvtf(cnvt,sizeof(cnvt),20,num);
+ if(strcmp("-1.867e+73",cnvt) != 0) {
+ fprintf(stderr,"Failed to convert numeric value %lf %s\n",num,cnvt);
+ failed_already = 1;
+ }
+
+ num = -1.867e-73;
+ num1 = PR_strtod("-1.867e-73",NULL);
+ if(num1 != num) {
+ fprintf(stderr,"Failed to convert numeric value %s\n","-1.867e-73");
+ failed_already = 1;
+ }
+
+ PR_cnvtf(cnvt,sizeof(cnvt),20,num);
+ if(strcmp("-1.867e-73",cnvt) != 0) {
+ fprintf(stderr,"Failed to convert numeric value %lf %s\n",num,cnvt);
+ failed_already = 1;
+ }
+
+ /* Testing for infinity */
+ num = 1.0 / zero;
+ num1 = PR_strtod("1.867e765",NULL);
+ if(num1 != num) {
+ fprintf(stderr,"Failed to convert numeric value %s\n","1.867e765");
+ failed_already = 1;
+ }
+
+ PR_cnvtf(cnvt,sizeof(cnvt),20,num);
+ if(strcmp("Infinity",cnvt) != 0) {
+ fprintf(stderr,"Failed to convert numeric value %lf %s\n",num,cnvt);
+ failed_already = 1;
+ }
+
+ num = -1.0 / zero;
+ num1 = PR_strtod("-1.867e765",NULL);
+ if(num1 != num) {
+ fprintf(stderr,"Failed to convert numeric value %s\n","-1.867e765");
+ failed_already = 1;
+ }
+
+ PR_cnvtf(cnvt,sizeof(cnvt),20,num);
+ if(strcmp("-Infinity",cnvt) != 0) {
+ fprintf(stderr,"Failed to convert numeric value %lf %s\n",num,cnvt);
+ failed_already = 1;
+ }
+
+ /* Testing for NaN. PR_strtod can't parse "NaN" and "Infinity" */
+ num = zero / zero;
+
+ PR_cnvtf(cnvt,sizeof(cnvt),20,num);
+ if(strcmp("NaN",cnvt) != 0) {
+ fprintf(stderr,"Failed to convert numeric value %lf %s\n",num,cnvt);
+ failed_already = 1;
+ }
+
+ num = - zero / zero;
+ PR_cnvtf(cnvt,sizeof(cnvt),20,num);
+ if(strcmp("NaN",cnvt) != 0) {
+ fprintf(stderr,"Failed to convert numeric value %lf %s\n",num,cnvt);
+ failed_already = 1;
+ }
+
+ num = 1.0000000001e21;
+ num1 = PR_strtod("1.0000000001e21",NULL);
+ if(num1 != num) {
+ fprintf(stderr,"Failed to convert numeric value %s\n",
+ "1.0000000001e21");
+ failed_already = 1;
+ }
+
+ PR_cnvtf(cnvt,sizeof(cnvt),20,num);
+ if(strcmp("1.0000000001e+21",cnvt) != 0) {
+ fprintf(stderr,"Failed to convert numeric value %lf %s\n",num,cnvt);
+ failed_already = 1;
+ }
+
+ num = -1.0000000001e-21;
+ num1 = PR_strtod("-1.0000000001e-21",NULL);
+ if(num1 != num) {
+ fprintf(stderr,"Failed to convert numeric value %s\n",
+ "-1.0000000001e-21");
+ failed_already = 1;
+ }
+ PR_cnvtf(cnvt,sizeof(cnvt),20,num);
+ if(strcmp("-1.0000000001e-21",cnvt) != 0) {
+ fprintf(stderr,"Failed to convert numeric value %lf %s\n",num,cnvt);
+ failed_already = 1;
+ }
+
+ /*
+ * Bug 414772: should not exit with "Zero passed to d2b" in debug
+ * build.
+ */
+ num1 = PR_strtod("4e-356",NULL);
+
+ /*
+ * A very long input with ~384K digits.
+ * Bug 516396: Should not crash.
+ * Bug 521306: Should return 0 without converting the input.
+ */
+#define LENGTH (384 * 1024)
+ thousands = (char *)malloc(LENGTH);
+ thousands[0] = '0';
+ thousands[1] = '.';
+ memset(&thousands[2], '1', LENGTH - 3);
+ thousands[LENGTH - 1] = '\0';
+ num = 0;
+ num1 = PR_strtod(thousands,NULL);
+ free(thousands);
+ if(num1 != num) {
+ fprintf(stderr,"Failed to convert numeric value %s\n",
+ "0.1111111111111111...");
+ failed_already = 1;
+ }
+
+ if (failed_already) {
+ printf("FAILED\n");
+ } else {
+ printf("PASSED\n");
+ }
+ return failed_already;
+}
diff --git a/nsprpub/pr/tests/env.c b/nsprpub/pr/tests/env.c
new file mode 100644
index 0000000000..17b0eeb9b8
--- /dev/null
+++ b/nsprpub/pr/tests/env.c
@@ -0,0 +1,370 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+** File: env.c
+** Description: Testing environment variable operations
+**
+*/
+#include "prenv.h"
+#include "prmem.h"
+#include "plgetopt.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+PRIntn debug = 0;
+PRIntn verbose = 0;
+PRIntn secure = 0;
+PRBool failedAlready = PR_FALSE;
+
+#define ENVNAME "NSPR_ENVIRONMENT_TEST_VARIABLE"
+#define ENVVALUE "The expected result"
+#define ENVBUFSIZE 256
+
+char *envBuf; /* buffer pointer. We leak memory here on purpose! */
+
+static char * NewBuffer( size_t size )
+{
+ char *buf = malloc( size );
+ if ( NULL == buf ) {
+ printf("env: NewBuffer() failed\n");
+ exit(1);
+ }
+ return(buf);
+} /* end NewBuffer() */
+
+int main(int argc, char **argv)
+{
+ char *value;
+ PRStatus rc;
+
+ { /* Get command line options */
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "vds");
+
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 'd': /* debug */
+ debug = 1;
+ break;
+ case 'v': /* verbose */
+ verbose = 1;
+ break;
+ case 's': /* secure / set[ug]id */
+ /*
+ ** To test PR_GetEnvSecure, make this executable (or a
+ ** copy of it) setuid / setgid / otherwise inherently
+ ** privileged (e.g., file capabilities) and run it
+ ** with this flag.
+ */
+ secure = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+ } /* end block "Get command line options" */
+
+#if 0
+ {
+ /*
+ ** This uses Windows native environment manipulation
+ ** as an experiment. Note the separation of namespace!
+ */
+ BOOL rv;
+ DWORD size;
+ rv = SetEnvironmentVariable( ENVNAME, ENVVALUE );
+ if ( rv == 0 ) {
+ if (debug) {
+ printf("env: Shit! SetEnvironmentVariable() failed\n");
+ }
+ failedAlready = PR_TRUE;
+ }
+ if (verbose) {
+ printf("env: SetEnvironmentVariable() worked\n");
+ }
+
+ size = GetEnvironmentVariable( ENVNAME, envBuf, ENVBUFSIZE );
+ if ( size == 0 ) {
+ if (debug) {
+ printf("env: Shit! GetEnvironmentVariable() failed. Found: %s\n", envBuf );
+ }
+ failedAlready = PR_TRUE;
+ }
+ if (verbose) {
+ printf("env: GetEnvironmentVariable() worked. Found: %s\n", envBuf);
+ }
+
+ value = PR_GetEnv( ENVNAME );
+ if ( (NULL == value ) || (strcmp( value, ENVVALUE))) {
+ if (debug) {
+ printf( "env: PR_GetEnv() failed retrieving WinNative. Found: %s\n", value);
+ }
+ failedAlready = PR_TRUE;
+ }
+ if (verbose) {
+ printf("env: PR_GetEnv() worked. Found: %s\n", value);
+ }
+ }
+#endif
+
+ /* set an environment variable, read it back */
+ envBuf = NewBuffer( ENVBUFSIZE );
+ sprintf( envBuf, ENVNAME "=" ENVVALUE );
+ rc = PR_SetEnv( envBuf );
+ if ( PR_FAILURE == rc ) {
+ if (debug) {
+ printf( "env: PR_SetEnv() failed setting\n");
+ }
+ failedAlready = PR_TRUE;
+ } else {
+ if (verbose) {
+ printf("env: PR_SetEnv() worked.\n");
+ }
+ }
+
+ value = PR_GetEnv( ENVNAME );
+ if ( (NULL == value ) || (strcmp( value, ENVVALUE))) {
+ if (debug) {
+ printf( "env: PR_GetEnv() Failed after setting\n" );
+ }
+ failedAlready = PR_TRUE;
+ } else {
+ if (verbose) {
+ printf("env: PR_GetEnv() worked after setting it. Found: %s\n", value );
+ }
+ }
+
+ if ( secure ) {
+ /*
+ ** In this case we've been run with elevated privileges, so
+ ** test that PR_GetEnvSecure *doesn't* find that env var.
+ */
+ value = PR_GetEnvSecure( ENVNAME );
+ if ( NULL != value ) {
+ if (debug) {
+ printf( "env: PR_GetEnvSecure() failed; expected NULL, found \"%s\"\n", value );
+ }
+ failedAlready = PR_TRUE;
+ } else {
+ if (verbose) {
+ printf("env: PR_GetEnvSecure() worked\n" );
+ }
+ }
+ } else {
+ /*
+ ** In this case the program is being run normally, so do the
+ ** same check for PR_GetEnvSecure as for PR_GetEnv.
+ */
+ value = PR_GetEnvSecure( ENVNAME );
+ if ( (NULL == value ) || (strcmp( value, ENVVALUE))) {
+ if (debug) {
+ printf( "env: PR_GetEnvSecure() Failed after setting\n" );
+ }
+ failedAlready = PR_TRUE;
+ } else {
+ if (verbose) {
+ printf("env: PR_GetEnvSecure() worked after setting it. Found: %s\n", value );
+ }
+ }
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* check that PR_DuplicateEnvironment() agrees with PR_GetEnv() */
+ {
+#if defined(XP_UNIX) && (!defined(DARWIN) || defined(HAVE_CRT_EXTERNS_H))
+ static const PRBool expect_failure = PR_FALSE;
+#else
+ static const PRBool expect_failure = PR_TRUE;
+#endif
+ char **i, **dupenv = PR_DuplicateEnvironment();
+
+
+ if ( NULL == dupenv ) {
+ if (expect_failure) {
+ if (verbose) printf("env: PR_DuplicateEnvironment failed, "
+ "as expected on this platform.\n");
+ } else {
+ if (debug) {
+ printf("env: PR_DuplicateEnvironment() failed.\n");
+ }
+ failedAlready = PR_TRUE;
+ }
+ } else {
+ unsigned found = 0;
+
+ if (expect_failure) {
+ if (debug) printf("env: PR_DuplicateEnvironment() succeeded, "
+ "but failure is expected on this platform.\n");
+ failedAlready = PR_TRUE;
+ } else {
+ if (verbose) {
+ printf("env: PR_DuplicateEnvironment() succeeded.\n");
+ }
+ }
+ for (i = dupenv; *i; i++) {
+ char *equals = strchr(*i, '=');
+
+ if ( equals == NULL ) {
+ if (debug) printf("env: PR_DuplicateEnvironment() returned a string"
+ " with no '=': %s\n", *i);
+ failedAlready = PR_TRUE;
+ } else {
+ /* We own this string, so we can temporarily alter it */
+ /* *i is the null-terminated name; equals + 1 is the value */
+ *equals = '\0';
+
+ if ( strcmp(*i, ENVNAME) == 0) {
+ found++;
+ if (verbose) printf("env: PR_DuplicateEnvironment() found " ENVNAME
+ " (%u so far).\n", found);
+ }
+
+ /* Multiple values for the same name can't happen, according to POSIX. */
+ value = PR_GetEnv(*i);
+ if ( value == NULL ) {
+ if (debug) printf("env: PR_DuplicateEnvironment() returned a name"
+ " which PR_GetEnv() failed to find: %s\n", *i);
+ failedAlready = PR_TRUE;
+ } else if ( strcmp(equals + 1, value) != 0) {
+ if (debug) printf("env: PR_DuplicateEnvironment() returned the wrong"
+ " value for %s: expected %s; found %s\n",
+ *i, value, equals + 1);
+ failedAlready = PR_TRUE;
+ } else {
+ if (verbose) printf("env: PR_DuplicateEnvironment() agreed with"
+ " PR_GetEnv() about %s\n", *i);
+ }
+ }
+ PR_Free(*i);
+ }
+ PR_Free(dupenv);
+
+ if (found != 1) {
+ if (debug) printf("env: PR_DuplicateEnvironment() found %u entries for " ENVNAME
+ " (expected 1)\n", found);
+ failedAlready = PR_TRUE;
+ } else {
+ if (verbose) {
+ printf("env: PR_DuplicateEnvironment() found 1 entry for " ENVNAME "\n");
+ }
+ }
+ }
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* un-set the variable, using RAW name... should not work */
+ envBuf = NewBuffer( ENVBUFSIZE );
+ sprintf( envBuf, ENVNAME );
+ rc = PR_SetEnv( envBuf );
+ if ( PR_FAILURE == rc ) {
+ if (verbose) {
+ printf( "env: PR_SetEnv() not un-set using RAW name. Good!\n");
+ }
+ } else {
+ if (debug) {
+ printf("env: PR_SetEnv() un-set using RAW name. Bad!\n" );
+ }
+ failedAlready = PR_TRUE;
+ }
+
+ value = PR_GetEnv( ENVNAME );
+ if ( NULL == value ) {
+ if (debug) {
+ printf("env: PR_GetEnv() after un-set using RAW name. Bad!\n" );
+ }
+ failedAlready = PR_TRUE;
+ } else {
+ if (verbose) {
+ printf( "env: PR_GetEnv() after RAW un-set found: %s\n", value );
+ }
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* set it again ... */
+ envBuf = NewBuffer( ENVBUFSIZE );
+ sprintf( envBuf, ENVNAME "=" ENVVALUE );
+ rc = PR_SetEnv( envBuf );
+ if ( PR_FAILURE == rc ) {
+ if (debug) {
+ printf( "env: PR_SetEnv() failed setting the second time.\n");
+ }
+ failedAlready = PR_TRUE;
+ } else {
+ if (verbose) {
+ printf("env: PR_SetEnv() worked.\n");
+ }
+ }
+
+ /* un-set the variable using the form name= */
+ envBuf = NewBuffer( ENVBUFSIZE );
+ sprintf( envBuf, ENVNAME "=" );
+ rc = PR_SetEnv( envBuf );
+ if ( PR_FAILURE == rc ) {
+ if (debug) {
+ printf( "env: PR_SetEnv() failed un-setting using name=\n");
+ }
+ failedAlready = PR_TRUE;
+ } else {
+ if (verbose) {
+ printf("env: PR_SetEnv() un-set using name= worked\n" );
+ }
+ }
+
+ value = PR_GetEnv( ENVNAME );
+ if (( NULL == value ) || ( 0x00 == *value )) {
+ if (verbose) {
+ printf("env: PR_GetEnv() after un-set using name= worked\n" );
+ }
+ } else {
+ if (debug) {
+ printf( "env: PR_GetEnv() after un-set using name=. Found: %s\n", value );
+ }
+ failedAlready = PR_TRUE;
+ }
+ /* ---------------------------------------------------------------------- */
+ /* un-set the variable using the form name= */
+ envBuf = NewBuffer( ENVBUFSIZE );
+ sprintf( envBuf, ENVNAME "999=" );
+ rc = PR_SetEnv( envBuf );
+ if ( PR_FAILURE == rc ) {
+ if (debug) {
+ printf( "env: PR_SetEnv() failed un-setting using name=\n");
+ }
+ failedAlready = PR_TRUE;
+ } else {
+ if (verbose) {
+ printf("env: PR_SetEnv() un-set using name= worked\n" );
+ }
+ }
+
+ value = PR_GetEnv( ENVNAME "999" );
+ if (( NULL == value ) || ( 0x00 == *value )) {
+ if (verbose) {
+ printf("env: PR_GetEnv() after un-set using name= worked\n" );
+ }
+ } else {
+ if (debug) {
+ printf( "env: PR_GetEnv() after un-set using name=. Found: %s\n", value );
+ }
+ failedAlready = PR_TRUE;
+ }
+
+ /* ---------------------------------------------------------------------- */
+ if (debug || verbose) {
+ printf("\n%s\n", (failedAlready)? "FAILED" : "PASSED" );
+ }
+ return( (failedAlready)? 1 : 0 );
+} /* main() */
+
+/* env.c */
diff --git a/nsprpub/pr/tests/errcodes.c b/nsprpub/pr/tests/errcodes.c
new file mode 100644
index 0000000000..591b630b23
--- /dev/null
+++ b/nsprpub/pr/tests/errcodes.c
@@ -0,0 +1,136 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/***********************************************************************
+**
+** Name: errcodes.c
+**
+** Description: print nspr error codes
+**
+*/
+#include "prerror.h"
+#include "plgetopt.h"
+
+#include <stdio.h>
+
+static int _debug_on = 0;
+
+struct errinfo {
+ PRErrorCode errcode;
+ char *errname;
+};
+
+struct errinfo errcodes[] = {
+ {PR_OUT_OF_MEMORY_ERROR, "PR_OUT_OF_MEMORY_ERROR"},
+ {PR_BAD_DESCRIPTOR_ERROR, "PR_BAD_DESCRIPTOR_ERROR"},
+ {PR_WOULD_BLOCK_ERROR, "PR_WOULD_BLOCK_ERROR"},
+ {PR_ACCESS_FAULT_ERROR, "PR_ACCESS_FAULT_ERROR"},
+ {PR_INVALID_METHOD_ERROR, "PR_INVALID_METHOD_ERROR"},
+ {PR_ILLEGAL_ACCESS_ERROR, "PR_ILLEGAL_ACCESS_ERROR"},
+ {PR_UNKNOWN_ERROR, "PR_UNKNOWN_ERROR"},
+ {PR_PENDING_INTERRUPT_ERROR, "PR_PENDING_INTERRUPT_ERROR"},
+ {PR_NOT_IMPLEMENTED_ERROR, "PR_NOT_IMPLEMENTED_ERROR"},
+ {PR_IO_ERROR, "PR_IO_ERROR"},
+ {PR_IO_TIMEOUT_ERROR, "PR_IO_TIMEOUT_ERROR"},
+ {PR_IO_PENDING_ERROR, "PR_IO_PENDING_ERROR"},
+ {PR_DIRECTORY_OPEN_ERROR, "PR_DIRECTORY_OPEN_ERROR"},
+ {PR_INVALID_ARGUMENT_ERROR, "PR_INVALID_ARGUMENT_ERROR"},
+ {PR_ADDRESS_NOT_AVAILABLE_ERROR, "PR_ADDRESS_NOT_AVAILABLE_ERROR"},
+ {PR_ADDRESS_NOT_SUPPORTED_ERROR, "PR_ADDRESS_NOT_SUPPORTED_ERROR"},
+ {PR_IS_CONNECTED_ERROR, "PR_IS_CONNECTED_ERROR"},
+ {PR_BAD_ADDRESS_ERROR, "PR_BAD_ADDRESS_ERROR"},
+ {PR_ADDRESS_IN_USE_ERROR, "PR_ADDRESS_IN_USE_ERROR"},
+ {PR_CONNECT_REFUSED_ERROR, "PR_CONNECT_REFUSED_ERROR"},
+ {PR_NETWORK_UNREACHABLE_ERROR, "PR_NETWORK_UNREACHABLE_ERROR"},
+ {PR_CONNECT_TIMEOUT_ERROR, "PR_CONNECT_TIMEOUT_ERROR"},
+ {PR_NOT_CONNECTED_ERROR, "PR_NOT_CONNECTED_ERROR"},
+ {PR_LOAD_LIBRARY_ERROR, "PR_LOAD_LIBRARY_ERROR"},
+ {PR_UNLOAD_LIBRARY_ERROR, "PR_UNLOAD_LIBRARY_ERROR"},
+ {PR_FIND_SYMBOL_ERROR, "PR_FIND_SYMBOL_ERROR"},
+ {PR_INSUFFICIENT_RESOURCES_ERROR, "PR_INSUFFICIENT_RESOURCES_ERROR"},
+ {PR_DIRECTORY_LOOKUP_ERROR, "PR_DIRECTORY_LOOKUP_ERROR"},
+ {PR_TPD_RANGE_ERROR, "PR_TPD_RANGE_ERROR"},
+ {PR_PROC_DESC_TABLE_FULL_ERROR, "PR_PROC_DESC_TABLE_FULL_ERROR"},
+ {PR_SYS_DESC_TABLE_FULL_ERROR, "PR_SYS_DESC_TABLE_FULL_ERROR"},
+ {PR_NOT_SOCKET_ERROR, "PR_NOT_SOCKET_ERROR"},
+ {PR_NOT_TCP_SOCKET_ERROR, "PR_NOT_TCP_SOCKET_ERROR"},
+ {PR_SOCKET_ADDRESS_IS_BOUND_ERROR, "PR_SOCKET_ADDRESS_IS_BOUND_ERROR"},
+ {PR_NO_ACCESS_RIGHTS_ERROR, "PR_NO_ACCESS_RIGHTS_ERROR"},
+ {PR_OPERATION_NOT_SUPPORTED_ERROR, "PR_OPERATION_NOT_SUPPORTED_ERROR"},
+ {PR_PROTOCOL_NOT_SUPPORTED_ERROR, "PR_PROTOCOL_NOT_SUPPORTED_ERROR"},
+ {PR_REMOTE_FILE_ERROR, "PR_REMOTE_FILE_ERROR"},
+ {PR_BUFFER_OVERFLOW_ERROR, "PR_BUFFER_OVERFLOW_ERROR"},
+ {PR_CONNECT_RESET_ERROR, "PR_CONNECT_RESET_ERROR"},
+ {PR_RANGE_ERROR, "PR_RANGE_ERROR"},
+ {PR_DEADLOCK_ERROR, "PR_DEADLOCK_ERROR"},
+ {PR_FILE_IS_LOCKED_ERROR, "PR_FILE_IS_LOCKED_ERROR"},
+ {PR_FILE_TOO_BIG_ERROR, "PR_FILE_TOO_BIG_ERROR"},
+ {PR_NO_DEVICE_SPACE_ERROR, "PR_NO_DEVICE_SPACE_ERROR"},
+ {PR_PIPE_ERROR, "PR_PIPE_ERROR"},
+ {PR_NO_SEEK_DEVICE_ERROR, "PR_NO_SEEK_DEVICE_ERROR"},
+ {PR_IS_DIRECTORY_ERROR, "PR_IS_DIRECTORY_ERROR"},
+ {PR_LOOP_ERROR, "PR_LOOP_ERROR"},
+ {PR_NAME_TOO_LONG_ERROR, "PR_NAME_TOO_LONG_ERROR"},
+ {PR_FILE_NOT_FOUND_ERROR, "PR_FILE_NOT_FOUND_ERROR"},
+ {PR_NOT_DIRECTORY_ERROR, "PR_NOT_DIRECTORY_ERROR"},
+ {PR_READ_ONLY_FILESYSTEM_ERROR, "PR_READ_ONLY_FILESYSTEM_ERROR"},
+ {PR_DIRECTORY_NOT_EMPTY_ERROR, "PR_DIRECTORY_NOT_EMPTY_ERROR"},
+ {PR_FILESYSTEM_MOUNTED_ERROR, "PR_FILESYSTEM_MOUNTED_ERROR"},
+ {PR_NOT_SAME_DEVICE_ERROR, "PR_NOT_SAME_DEVICE_ERROR"},
+ {PR_DIRECTORY_CORRUPTED_ERROR, "PR_DIRECTORY_CORRUPTED_ERROR"},
+ {PR_FILE_EXISTS_ERROR, "PR_FILE_EXISTS_ERROR"},
+ {PR_MAX_DIRECTORY_ENTRIES_ERROR, "PR_MAX_DIRECTORY_ENTRIES_ERROR"},
+ {PR_INVALID_DEVICE_STATE_ERROR, "PR_INVALID_DEVICE_STATE_ERROR"},
+ {PR_DEVICE_IS_LOCKED_ERROR, "PR_DEVICE_IS_LOCKED_ERROR"},
+ {PR_NO_MORE_FILES_ERROR, "PR_NO_MORE_FILES_ERROR"},
+ {PR_END_OF_FILE_ERROR, "PR_END_OF_FILE_ERROR"},
+ {PR_FILE_SEEK_ERROR, "PR_FILE_SEEK_ERROR"},
+ {PR_FILE_IS_BUSY_ERROR, "PR_FILE_IS_BUSY_ERROR"},
+ {PR_IN_PROGRESS_ERROR, "PR_IN_PROGRESS_ERROR"},
+ {PR_ALREADY_INITIATED_ERROR, "PR_ALREADY_INITIATED_ERROR"},
+ {PR_GROUP_EMPTY_ERROR, "PR_GROUP_EMPTY_ERROR"},
+ {PR_INVALID_STATE_ERROR, "PR_INVALID_STATE_ERROR"},
+ {PR_NETWORK_DOWN_ERROR, "PR_NETWORK_DOWN_ERROR"},
+ {PR_SOCKET_SHUTDOWN_ERROR, "PR_SOCKET_SHUTDOWN_ERROR"},
+ {PR_CONNECT_ABORTED_ERROR, "PR_CONNECT_ABORTED_ERROR"},
+ {PR_HOST_UNREACHABLE_ERROR, "PR_HOST_UNREACHABLE_ERROR"}
+};
+
+int main(int argc, char **argv)
+{
+
+ int count, errnum;
+
+ /*
+ * -d debug mode
+ */
+
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "d");
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 'd': /* debug mode */
+ _debug_on = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ count = sizeof(errcodes)/sizeof(errcodes[0]);
+ printf("\nNumber of error codes = %d\n\n",count);
+ for (errnum = 0; errnum < count; errnum++) {
+ printf("%-40s = %d\n",errcodes[errnum].errname,
+ errcodes[errnum].errcode);
+ }
+
+ return 0;
+}
diff --git a/nsprpub/pr/tests/errset.c b/nsprpub/pr/tests/errset.c
new file mode 100644
index 0000000000..fb76a6fa9d
--- /dev/null
+++ b/nsprpub/pr/tests/errset.c
@@ -0,0 +1,155 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/***********************************************************************
+**
+** Name: errset.c
+**
+** Description: errset.c exercises the functions in prerror.c.
+** This code is a unit test of the prerror.c capability.
+**
+** Note: There's some fluff in here. The guts of the test
+** were plagerized from another test. So, sue me.
+**
+**
+*/
+#include "prerror.h"
+#include "plgetopt.h"
+#include "prlog.h"
+
+#include <stdio.h>
+#include <string.h>
+
+static int _debug_on = 0;
+
+struct errinfo {
+ PRErrorCode errcode;
+ char *errname;
+};
+
+struct errinfo errcodes[] = {
+ {PR_OUT_OF_MEMORY_ERROR, "PR_OUT_OF_MEMORY_ERROR"},
+ {PR_UNKNOWN_ERROR, "An intentionally long error message text intended to force a delete of the current errorString buffer and get another one."},
+ {PR_BAD_DESCRIPTOR_ERROR, "PR_BAD_DESCRIPTOR_ERROR"},
+ {PR_WOULD_BLOCK_ERROR, "PR_WOULD_BLOCK_ERROR"},
+ {PR_ACCESS_FAULT_ERROR, "PR_ACCESS_FAULT_ERROR"},
+ {PR_INVALID_METHOD_ERROR, "PR_INVALID_METHOD_ERROR"},
+ {PR_ILLEGAL_ACCESS_ERROR, "PR_ILLEGAL_ACCESS_ERROR"},
+ {PR_UNKNOWN_ERROR, "PR_UNKNOWN_ERROR"},
+ {PR_PENDING_INTERRUPT_ERROR, "PR_PENDING_INTERRUPT_ERROR"},
+ {PR_NOT_IMPLEMENTED_ERROR, "PR_NOT_IMPLEMENTED_ERROR"},
+ {PR_IO_ERROR, "PR_IO_ERROR"},
+ {PR_IO_TIMEOUT_ERROR, "PR_IO_TIMEOUT_ERROR"},
+ {PR_IO_PENDING_ERROR, "PR_IO_PENDING_ERROR"},
+ {PR_DIRECTORY_OPEN_ERROR, "PR_DIRECTORY_OPEN_ERROR"},
+ {PR_INVALID_ARGUMENT_ERROR, "PR_INVALID_ARGUMENT_ERROR"},
+ {PR_ADDRESS_NOT_AVAILABLE_ERROR, "PR_ADDRESS_NOT_AVAILABLE_ERROR"},
+ {PR_ADDRESS_NOT_SUPPORTED_ERROR, "PR_ADDRESS_NOT_SUPPORTED_ERROR"},
+ {PR_IS_CONNECTED_ERROR, "PR_IS_CONNECTED_ERROR"},
+ {PR_BAD_ADDRESS_ERROR, "PR_BAD_ADDRESS_ERROR"},
+ {PR_ADDRESS_IN_USE_ERROR, "PR_ADDRESS_IN_USE_ERROR"},
+ {PR_CONNECT_REFUSED_ERROR, "PR_CONNECT_REFUSED_ERROR"},
+ {PR_NETWORK_UNREACHABLE_ERROR, "PR_NETWORK_UNREACHABLE_ERROR"},
+ {PR_CONNECT_TIMEOUT_ERROR, "PR_CONNECT_TIMEOUT_ERROR"},
+ {PR_NOT_CONNECTED_ERROR, "PR_NOT_CONNECTED_ERROR"},
+ {PR_LOAD_LIBRARY_ERROR, "PR_LOAD_LIBRARY_ERROR"},
+ {PR_UNLOAD_LIBRARY_ERROR, "PR_UNLOAD_LIBRARY_ERROR"},
+ {PR_FIND_SYMBOL_ERROR, "PR_FIND_SYMBOL_ERROR"},
+ {PR_INSUFFICIENT_RESOURCES_ERROR, "PR_INSUFFICIENT_RESOURCES_ERROR"},
+ {PR_DIRECTORY_LOOKUP_ERROR, "PR_DIRECTORY_LOOKUP_ERROR"},
+ {PR_TPD_RANGE_ERROR, "PR_TPD_RANGE_ERROR"},
+ {PR_PROC_DESC_TABLE_FULL_ERROR, "PR_PROC_DESC_TABLE_FULL_ERROR"},
+ {PR_SYS_DESC_TABLE_FULL_ERROR, "PR_SYS_DESC_TABLE_FULL_ERROR"},
+ {PR_NOT_SOCKET_ERROR, "PR_NOT_SOCKET_ERROR"},
+ {PR_NOT_TCP_SOCKET_ERROR, "PR_NOT_TCP_SOCKET_ERROR"},
+ {PR_SOCKET_ADDRESS_IS_BOUND_ERROR, "PR_SOCKET_ADDRESS_IS_BOUND_ERROR"},
+ {PR_NO_ACCESS_RIGHTS_ERROR, "PR_NO_ACCESS_RIGHTS_ERROR"},
+ {PR_OPERATION_NOT_SUPPORTED_ERROR, "PR_OPERATION_NOT_SUPPORTED_ERROR"},
+ {PR_PROTOCOL_NOT_SUPPORTED_ERROR, "PR_PROTOCOL_NOT_SUPPORTED_ERROR"},
+ {PR_REMOTE_FILE_ERROR, "PR_REMOTE_FILE_ERROR"},
+ {PR_BUFFER_OVERFLOW_ERROR, "PR_BUFFER_OVERFLOW_ERROR"},
+ {PR_CONNECT_RESET_ERROR, "PR_CONNECT_RESET_ERROR"},
+ {PR_RANGE_ERROR, "PR_RANGE_ERROR"},
+ {PR_DEADLOCK_ERROR, "PR_DEADLOCK_ERROR"},
+ {PR_FILE_IS_LOCKED_ERROR, "PR_FILE_IS_LOCKED_ERROR"},
+ {PR_FILE_TOO_BIG_ERROR, "PR_FILE_TOO_BIG_ERROR"},
+ {PR_NO_DEVICE_SPACE_ERROR, "PR_NO_DEVICE_SPACE_ERROR"},
+ {PR_PIPE_ERROR, "PR_PIPE_ERROR"},
+ {PR_NO_SEEK_DEVICE_ERROR, "PR_NO_SEEK_DEVICE_ERROR"},
+ {PR_IS_DIRECTORY_ERROR, "PR_IS_DIRECTORY_ERROR"},
+ {PR_LOOP_ERROR, "PR_LOOP_ERROR"},
+ {PR_NAME_TOO_LONG_ERROR, "PR_NAME_TOO_LONG_ERROR"},
+ {PR_FILE_NOT_FOUND_ERROR, "PR_FILE_NOT_FOUND_ERROR"},
+ {PR_NOT_DIRECTORY_ERROR, "PR_NOT_DIRECTORY_ERROR"},
+ {PR_READ_ONLY_FILESYSTEM_ERROR, "PR_READ_ONLY_FILESYSTEM_ERROR"},
+ {PR_DIRECTORY_NOT_EMPTY_ERROR, "PR_DIRECTORY_NOT_EMPTY_ERROR"},
+ {PR_FILESYSTEM_MOUNTED_ERROR, "PR_FILESYSTEM_MOUNTED_ERROR"},
+ {PR_NOT_SAME_DEVICE_ERROR, "PR_NOT_SAME_DEVICE_ERROR"},
+ {PR_DIRECTORY_CORRUPTED_ERROR, "PR_DIRECTORY_CORRUPTED_ERROR"},
+ {PR_FILE_EXISTS_ERROR, "PR_FILE_EXISTS_ERROR"},
+ {PR_MAX_DIRECTORY_ENTRIES_ERROR, "PR_MAX_DIRECTORY_ENTRIES_ERROR"},
+ {PR_INVALID_DEVICE_STATE_ERROR, "PR_INVALID_DEVICE_STATE_ERROR"},
+ {PR_DEVICE_IS_LOCKED_ERROR, "PR_DEVICE_IS_LOCKED_ERROR"},
+ {PR_NO_MORE_FILES_ERROR, "PR_NO_MORE_FILES_ERROR"},
+ {PR_END_OF_FILE_ERROR, "PR_END_OF_FILE_ERROR"},
+ {PR_FILE_SEEK_ERROR, "PR_FILE_SEEK_ERROR"},
+ {PR_FILE_IS_BUSY_ERROR, "PR_FILE_IS_BUSY_ERROR"},
+ {PR_IN_PROGRESS_ERROR, "PR_IN_PROGRESS_ERROR"},
+ {PR_ALREADY_INITIATED_ERROR, "PR_ALREADY_INITIATED_ERROR"},
+ {PR_GROUP_EMPTY_ERROR, "PR_GROUP_EMPTY_ERROR"},
+ {PR_INVALID_STATE_ERROR, "PR_INVALID_STATE_ERROR"},
+ {PR_NETWORK_DOWN_ERROR, "PR_NETWORK_DOWN_ERROR"},
+ {PR_SOCKET_SHUTDOWN_ERROR, "PR_SOCKET_SHUTDOWN_ERROR"},
+ {PR_CONNECT_ABORTED_ERROR, "PR_CONNECT_ABORTED_ERROR"},
+ {PR_HOST_UNREACHABLE_ERROR, "PR_HOST_UNREACHABLE_ERROR"}
+};
+
+int main(int argc, char **argv)
+{
+
+ int count, errnum;
+
+ /*
+ * -d debug mode
+ */
+
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "d");
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 'd': /* debug mode */
+ _debug_on = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ count = sizeof(errcodes)/sizeof(errcodes[0]);
+ printf("\nNumber of error codes = %d\n\n",count);
+ for (errnum = 0; errnum < count; errnum++) {
+ PRInt32 len1, len2, err;
+ char msg[256];
+
+ PR_SetError( errnum, -5 );
+ err = PR_GetError();
+ PR_ASSERT( err == errnum );
+ err = PR_GetOSError();
+ PR_ASSERT( err == -5 );
+ PR_SetErrorText( strlen(errcodes[errnum].errname), errcodes[errnum].errname );
+ len1 = PR_GetErrorTextLength();
+ len2 = PR_GetErrorText( msg );
+ PR_ASSERT( len1 == len2 );
+ printf("%5.5d -- %s\n", errnum, msg );
+ }
+
+ return 0;
+}
diff --git a/nsprpub/pr/tests/exit.c b/nsprpub/pr/tests/exit.c
new file mode 100644
index 0000000000..dd3d44427e
--- /dev/null
+++ b/nsprpub/pr/tests/exit.c
@@ -0,0 +1,110 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "prio.h"
+#include "prprf.h"
+#include "prinit.h"
+#include "prthread.h"
+#include "prproces.h"
+#include "prinrval.h"
+
+#include "plgetopt.h"
+
+#include <stdlib.h>
+
+static PRInt32 dally = 0;
+static PRFileDesc *err = NULL;
+static PRBool verbose = PR_FALSE, force = PR_FALSE;
+
+static void Help(void)
+{
+ PR_fprintf(err, "Usage: [-t s] [-h]\n");
+ PR_fprintf(err, "\t-d Verbose output (default: FALSE)\n");
+ PR_fprintf(err, "\t-x Forced termination (default: FALSE)\n");
+ PR_fprintf(err, "\t-t Time for thread to block (default: 10 seconds)\n");
+ PR_fprintf(err, "\t-h This message and nothing else\n");
+} /* Help */
+
+static void Dull(void *arg)
+{
+ PR_Sleep(PR_SecondsToInterval(dally));
+ if (verbose && force) {
+ PR_fprintf(err, "If you see this, the test failed\n");
+ }
+} /* Dull */
+
+static PRIntn PR_CALLBACK RealMain(PRIntn argc, char **argv)
+{
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "ht:dx");
+
+ err = PR_GetSpecialFD(PR_StandardError);
+
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 'd': /* verbosity */
+ verbose = PR_TRUE;
+ break;
+ case 'x': /* force exit */
+ force = PR_TRUE;
+ break;
+ case 't': /* seconds to dally in child */
+ dally = atoi(opt->value);
+ break;
+ case 'h': /* user wants some guidance */
+ default:
+ Help(); /* so give him an earful */
+ return 2; /* but not a lot else */
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ if (0 == dally) {
+ dally = 10;
+ }
+
+ /*
+ * Create LOCAL and GLOBAL threads
+ */
+ (void)PR_CreateThread(
+ PR_USER_THREAD, Dull, NULL, PR_PRIORITY_NORMAL,
+ PR_LOCAL_THREAD, PR_UNJOINABLE_THREAD, 0);
+
+ (void)PR_CreateThread(
+ PR_USER_THREAD, Dull, NULL, PR_PRIORITY_NORMAL,
+ PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD, 0);
+
+ if (verbose)
+ PR_fprintf(
+ err, "Main is exiting now. Program should exit %s.\n",
+ (force) ? "immediately" : "after child dally time");
+
+ if (force)
+ {
+ PR_ProcessExit(0);
+ if (verbose)
+ {
+ PR_fprintf(err, "You should not have gotten here.\n");
+ return 1;
+ }
+ }
+ return 0;
+
+}
+
+
+int main(int argc, char **argv)
+{
+ PRIntn rv;
+
+ PR_STDIO_INIT();
+ rv = PR_Initialize(RealMain, argc, argv, 0);
+ return rv;
+} /* main */
diff --git a/nsprpub/pr/tests/fdcach.c b/nsprpub/pr/tests/fdcach.c
new file mode 100644
index 0000000000..5fa51b706a
--- /dev/null
+++ b/nsprpub/pr/tests/fdcach.c
@@ -0,0 +1,125 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * File: fdcach.c
+ * Description:
+ * This test verifies that the fd cache is working
+ * correctly.
+ */
+
+#include "nspr.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+/*
+ * Define ORDER_PRESERVED if the implementation of PR_SetFDCacheSize
+ * preserves the ordering of the fd's when moving them between the
+ * cache.
+ */
+#define ORDER_PRESERVED 1
+
+/*
+ * NUM_FDS must be <= FD_CACHE_SIZE.
+ */
+#define FD_CACHE_SIZE 1024
+#define NUM_FDS 20
+
+int main(int argc, char **argv)
+{
+ int i;
+ PRFileDesc *fds[NUM_FDS];
+ PRFileDesc *savefds[NUM_FDS];
+ int numfds = sizeof(fds)/sizeof(fds[0]);
+
+ PR_SetFDCacheSize(0, FD_CACHE_SIZE);
+
+ /* Add some fd's to the fd cache. */
+ for (i = 0; i < numfds; i++) {
+ savefds[i] = PR_NewTCPSocket();
+ if (NULL == savefds[i]) {
+ fprintf(stderr, "PR_NewTCPSocket failed\n");
+ exit(1);
+ }
+ }
+ for (i = 0; i < numfds; i++) {
+ if (PR_Close(savefds[i]) == PR_FAILURE) {
+ fprintf(stderr, "PR_Close failed\n");
+ exit(1);
+ }
+ }
+
+ /*
+ * Create some fd's. These fd's should come from
+ * the fd cache. Verify the FIFO ordering of the fd
+ * cache.
+ */
+ for (i = 0; i < numfds; i++) {
+ fds[i] = PR_NewTCPSocket();
+ if (NULL == fds[i]) {
+ fprintf(stderr, "PR_NewTCPSocket failed\n");
+ exit(1);
+ }
+ if (fds[i] != savefds[i]) {
+ fprintf(stderr, "fd cache malfunctioned\n");
+ exit(1);
+ }
+ }
+ /* Put the fd's back to the fd cache. */
+ for (i = 0; i < numfds; i++) {
+ if (PR_Close(savefds[i]) == PR_FAILURE) {
+ fprintf(stderr, "PR_Close failed\n");
+ exit(1);
+ }
+ }
+
+ /* Switch to the fd cache. */
+ PR_SetFDCacheSize(0, FD_CACHE_SIZE);
+
+ for (i = 0; i < numfds; i++) {
+ fds[i] = PR_NewTCPSocket();
+ if (NULL == fds[i]) {
+ fprintf(stderr, "PR_NewTCPSocket failed\n");
+ exit(1);
+ }
+#ifdef ORDER_PRESERVED
+ if (fds[i] != savefds[i]) {
+ fprintf(stderr, "fd cache malfunctioned\n");
+ exit(1);
+ }
+#else
+ savefds[i] = fds[i];
+#endif
+ }
+ for (i = 0; i < numfds; i++) {
+ if (PR_Close(savefds[i]) == PR_FAILURE) {
+ fprintf(stderr, "PR_Close failed\n");
+ exit(1);
+ }
+ }
+
+ for (i = 0; i < numfds; i++) {
+ fds[i] = PR_NewTCPSocket();
+ if (NULL == fds[i]) {
+ fprintf(stderr, "PR_NewTCPSocket failed\n");
+ exit(1);
+ }
+ if (fds[i] != savefds[i]) {
+ fprintf(stderr, "fd cache malfunctioned\n");
+ exit(1);
+ }
+ }
+ for (i = 0; i < numfds; i++) {
+ if (PR_Close(savefds[i]) == PR_FAILURE) {
+ fprintf(stderr, "PR_Close failed\n");
+ exit(1);
+ }
+ }
+
+ PR_Cleanup();
+ printf("PASS\n");
+ return 0;
+}
diff --git a/nsprpub/pr/tests/fileio.c b/nsprpub/pr/tests/fileio.c
new file mode 100644
index 0000000000..a0be3bb10a
--- /dev/null
+++ b/nsprpub/pr/tests/fileio.c
@@ -0,0 +1,214 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/***********************************************************************
+**
+** Name: fileio.c
+**
+** Description: Program to copy one file to another.
+**
+** Modification History:
+** 14-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
+** The debug mode will print all of the printfs associated with this test.
+** The regress mode will be the default mode. Since the regress tool limits
+** the output to a one line status:PASS or FAIL,all of the printf statements
+** have been handled with an if (debug_mode) statement.
+** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to
+** recognize the return code from tha main program.
+** 12-June-97 Revert to return code 0 and 1, remove debug option (obsolete).
+***********************************************************************/
+
+/***********************************************************************
+** Includes
+***********************************************************************/
+#include "prinit.h"
+#include "prthread.h"
+#include "prlock.h"
+#include "prcvar.h"
+#include "prmon.h"
+#include "prmem.h"
+#include "prio.h"
+#include "prlog.h"
+
+#include <stdio.h>
+
+#include "obsolete/prsem.h"
+
+
+#define TBSIZE 1024
+
+static PRUint8 tbuf[TBSIZE];
+
+static PRFileDesc *t1, *t2;
+
+PRIntn failed_already=0;
+PRIntn debug_mode;
+static void InitialSetup(void)
+{
+ PRUintn i;
+ PRInt32 nWritten, rv;
+
+ t1 = PR_Open("t1.tmp", PR_CREATE_FILE | PR_RDWR, 0);
+ PR_ASSERT(t1 != NULL);
+
+ for (i=0; i<TBSIZE; i++) {
+ tbuf[i] = i;
+ }
+
+ nWritten = PR_Write((PRFileDesc*)t1, tbuf, TBSIZE);
+ PR_ASSERT(nWritten == TBSIZE);
+
+ rv = PR_Seek(t1,0,PR_SEEK_SET);
+ PR_ASSERT(rv == 0);
+
+ t2 = PR_Open("t2.tmp", PR_CREATE_FILE | PR_RDWR, 0);
+ PR_ASSERT(t2 != NULL);
+}
+
+
+static void VerifyAndCleanup(void)
+{
+ PRUintn i;
+ PRInt32 nRead, rv;
+
+ for (i=0; i<TBSIZE; i++) {
+ tbuf[i] = 0;
+ }
+
+ rv = PR_Seek(t2,0,PR_SEEK_SET);
+ PR_ASSERT(rv == 0);
+
+ nRead = PR_Read((PRFileDesc*)t2, tbuf, TBSIZE);
+ PR_ASSERT(nRead == TBSIZE);
+
+ for (i=0; i<TBSIZE; i++)
+ if (tbuf[i] != (PRUint8)i) {
+ if (debug_mode) {
+ printf("data mismatch for index= %d \n", i);
+ }
+ else {
+ failed_already=1;
+ }
+ }
+ PR_Close(t1);
+ PR_Close(t2);
+
+ PR_Delete("t1.tmp");
+ PR_Delete("t2.tmp");
+
+ if (debug_mode) {
+ printf("fileio test passed\n");
+ }
+}
+
+
+/*------------------ Following is the real test program ---------*/
+/*
+ Program to copy one file to another. Two temporary files get
+ created. First one gets written in one write call. Then,
+ a reader thread reads from this file into a double buffer.
+ The writer thread writes from double buffer into the other
+ temporary file. The second temporary file gets verified
+ for accurate data.
+*/
+
+PRSemaphore *emptyBufs; /* number of empty buffers */
+PRSemaphore *fullBufs; /* number of buffers that are full */
+
+#define BSIZE 100
+
+struct {
+ char data[BSIZE];
+ PRUintn nbytes; /* number of bytes in this buffer */
+} buf[2];
+
+static void PR_CALLBACK reader(void *arg)
+{
+ PRUintn i = 0;
+ PRInt32 nbytes;
+
+ do {
+ (void) PR_WaitSem(emptyBufs);
+ nbytes = PR_Read((PRFileDesc*)arg, buf[i].data, BSIZE);
+ if (nbytes >= 0) {
+ buf[i].nbytes = nbytes;
+ PR_PostSem(fullBufs);
+ i = (i + 1) % 2;
+ }
+ } while (nbytes > 0);
+}
+
+static void PR_CALLBACK writer(void *arg)
+{
+ PRUintn i = 0;
+ PRInt32 nbytes;
+
+ do {
+ (void) PR_WaitSem(fullBufs);
+ nbytes = buf[i].nbytes;
+ if (nbytes > 0) {
+ nbytes = PR_Write((PRFileDesc*)arg, buf[i].data, nbytes);
+ PR_PostSem(emptyBufs);
+ i = (i + 1) % 2;
+ }
+ } while (nbytes > 0);
+}
+
+int main(int argc, char **argv)
+{
+ PRThread *r, *w;
+
+
+ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
+ PR_STDIO_INIT();
+
+ emptyBufs = PR_NewSem(2); /* two empty buffers */
+
+ fullBufs = PR_NewSem(0); /* zero full buffers */
+
+ /* Create initial temp file setup */
+ InitialSetup();
+
+ /* create the reader thread */
+
+ r = PR_CreateThread(PR_USER_THREAD,
+ reader, t1,
+ PR_PRIORITY_NORMAL,
+ PR_LOCAL_THREAD,
+ PR_JOINABLE_THREAD,
+ 0);
+
+ w = PR_CreateThread(PR_USER_THREAD,
+ writer, t2,
+ PR_PRIORITY_NORMAL,
+ PR_LOCAL_THREAD,
+ PR_JOINABLE_THREAD,
+ 0);
+
+ /* Do the joining for both threads */
+ (void) PR_JoinThread(r);
+ (void) PR_JoinThread(w);
+
+ /* Do the verification and clean up */
+ VerifyAndCleanup();
+
+ PR_DestroySem(emptyBufs);
+ PR_DestroySem(fullBufs);
+
+ PR_Cleanup();
+
+ if(failed_already)
+ {
+ printf("Fail\n");
+ return 1;
+ }
+ else
+ {
+ printf("PASS\n");
+ return 0;
+ }
+
+
+}
diff --git a/nsprpub/pr/tests/foreign.c b/nsprpub/pr/tests/foreign.c
new file mode 100644
index 0000000000..a1f5b5cbcc
--- /dev/null
+++ b/nsprpub/pr/tests/foreign.c
@@ -0,0 +1,321 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+** File: foreign.c
+** Description: Testing various functions w/ foreign threads
+**
+** We create a thread and get it to call exactly one runtime function.
+** The thread is allowed to be created by some other environment that
+** NSPR, but it does not announce itself to the runtime prior to calling
+** in.
+**
+** The goal: try to survive.
+**
+*/
+
+#include "prcvar.h"
+#include "prenv.h"
+#include "prerror.h"
+#include "prinit.h"
+#include "prinrval.h"
+#include "prio.h"
+#include "prlock.h"
+#include "prlog.h"
+#include "prmem.h"
+#include "prthread.h"
+#include "prtypes.h"
+#include "prprf.h"
+#include "plgetopt.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+static enum {
+ thread_nspr, thread_pthread, thread_sproc, thread_win32
+} thread_provider;
+
+typedef void (*StartFn)(void*);
+typedef struct StartObject
+{
+ StartFn start;
+ void *arg;
+} StartObject;
+
+static PRFileDesc *output;
+
+static int _debug_on = 0;
+
+#define DEFAULT_THREAD_COUNT 10
+
+#define DPRINTF(arg) if (_debug_on) PR_fprintf arg
+
+#if defined(_PR_PTHREADS)
+#include <pthread.h>
+#include "md/_pth.h"
+static void *pthread_start(void *arg)
+{
+ StartFn start = ((StartObject*)arg)->start;
+ void *data = ((StartObject*)arg)->arg;
+ PR_Free(arg);
+ start(data);
+ return NULL;
+} /* pthread_start */
+#endif /* defined(_PR_PTHREADS) */
+
+#if defined(WIN32)
+#include <windows.h>
+#include <process.h> /* for _beginthreadex() */
+
+static PRUintn __stdcall windows_start(void *arg)
+{
+ StartObject *so = (StartObject*)arg;
+ StartFn start = so->start;
+ void *data = so->arg;
+ PR_Free(so);
+ start(data);
+ return 0;
+} /* windows_start */
+#endif /* defined(WIN32) */
+
+static PRStatus NSPRPUB_TESTS_CreateThread(StartFn start, void *arg)
+{
+ PRStatus rv;
+
+ switch (thread_provider)
+ {
+ case thread_nspr:
+ {
+ PRThread *thread = PR_CreateThread(
+ PR_USER_THREAD, start, arg,
+ PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
+ PR_UNJOINABLE_THREAD, 0);
+ rv = (NULL == thread) ? PR_FAILURE : PR_SUCCESS;
+ }
+ break;
+ case thread_pthread:
+#if defined(_PR_PTHREADS)
+ {
+ int rv;
+ pthread_t id;
+ pthread_attr_t tattr;
+ StartObject *start_object;
+ start_object = PR_NEW(StartObject);
+ PR_ASSERT(NULL != start_object);
+ start_object->start = start;
+ start_object->arg = arg;
+
+ rv = _PT_PTHREAD_ATTR_INIT(&tattr);
+ PR_ASSERT(0 == rv);
+
+ rv = pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
+ PR_ASSERT(0 == rv);
+
+ rv = pthread_attr_setstacksize(&tattr, 64 * 1024);
+ PR_ASSERT(0 == rv);
+
+ rv = _PT_PTHREAD_CREATE(&id, tattr, pthread_start, start_object);
+ (void)_PT_PTHREAD_ATTR_DESTROY(&tattr);
+ return (0 == rv) ? PR_SUCCESS : PR_FAILURE;
+ }
+#else
+ PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+ rv = PR_FAILURE;
+ break;
+#endif /* defined(_PR_PTHREADS) */
+
+ case thread_sproc:
+ PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+ rv = PR_FAILURE;
+ break;
+ case thread_win32:
+#if defined(WIN32)
+ {
+ void *th;
+ PRUintn id;
+ StartObject *start_object;
+ start_object = PR_NEW(StartObject);
+ PR_ASSERT(NULL != start_object);
+ start_object->start = start;
+ start_object->arg = arg;
+ th = (void*)_beginthreadex(
+ NULL, /* LPSECURITY_ATTRIBUTES - pointer to thread security attributes */
+ 0U, /* DWORD - initial thread stack size, in bytes */
+ windows_start, /* LPTHREAD_START_ROUTINE - pointer to thread function */
+ start_object, /* LPVOID - argument for new thread */
+ STACK_SIZE_PARAM_IS_A_RESERVATION, /*DWORD dwCreationFlags - creation flags */
+ &id /* LPDWORD - pointer to returned thread identifier */ );
+
+ rv = (NULL == th) ? PR_FAILURE : PR_SUCCESS;
+ }
+#else
+ PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+ rv = PR_FAILURE;
+#endif
+ break;
+ default:
+ PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+ rv = PR_FAILURE;
+ }
+ return rv;
+} /* NSPRPUB_TESTS_CreateThread */
+
+static void PR_CALLBACK lazyEntry(void *arg)
+{
+ PR_ASSERT(NULL == arg);
+} /* lazyEntry */
+
+
+static void OneShot(void *arg)
+{
+ PRUintn pdkey;
+ PRLock *lock;
+ PRFileDesc *fd;
+ PRDir *dir;
+ PRFileDesc *pair[2];
+ PRIntn test = (PRIntn)arg;
+
+ for (test = 0; test < 12; ++test) {
+
+ switch (test)
+ {
+ case 0:
+ lock = PR_NewLock();
+ DPRINTF((output,"Thread[0x%x] called PR_NewLock\n",
+ PR_GetCurrentThread()));
+ PR_DestroyLock(lock);
+ break;
+
+ case 1:
+ (void)PR_SecondsToInterval(1);
+ DPRINTF((output,"Thread[0x%x] called PR_SecondsToInterval\n",
+ PR_GetCurrentThread()));
+ break;
+
+ case 2: (void)PR_CreateThread(
+ PR_USER_THREAD, lazyEntry, NULL, PR_PRIORITY_NORMAL,
+ PR_LOCAL_THREAD, PR_UNJOINABLE_THREAD, 0);
+ DPRINTF((output,"Thread[0x%x] called PR_CreateThread\n",
+ PR_GetCurrentThread()));
+ break;
+
+ case 3:
+ fd = PR_Open("foreign.tmp", PR_CREATE_FILE | PR_RDWR, 0666);
+ DPRINTF((output,"Thread[0x%x] called PR_Open\n",
+ PR_GetCurrentThread()));
+ PR_Close(fd);
+ break;
+
+ case 4:
+ fd = PR_NewUDPSocket();
+ DPRINTF((output,"Thread[0x%x] called PR_NewUDPSocket\n",
+ PR_GetCurrentThread()));
+ PR_Close(fd);
+ break;
+
+ case 5:
+ fd = PR_NewTCPSocket();
+ DPRINTF((output,"Thread[0x%x] called PR_NewTCPSocket\n",
+ PR_GetCurrentThread()));
+ PR_Close(fd);
+ break;
+
+ case 6:
+#define TEMP_DIR "./tmp"
+ PR_MkDir(TEMP_DIR, 0700);
+ dir = PR_OpenDir(TEMP_DIR);
+ DPRINTF((output,"Thread[0x%x] called PR_OpenDir\n",
+ PR_GetCurrentThread()));
+ PR_CloseDir(dir);
+ break;
+
+ case 7:
+ (void)PR_NewThreadPrivateIndex(&pdkey, NULL);
+ DPRINTF((output,"Thread[0x%x] called PR_NewThreadPrivateIndex\n",
+ PR_GetCurrentThread()));
+ break;
+
+ case 8:
+ (void)PR_GetEnv("PATH");
+ DPRINTF((output,"Thread[0x%x] called PR_GetEnv\n",
+ PR_GetCurrentThread()));
+ break;
+
+ case 9:
+ (void)PR_NewTCPSocketPair(pair);
+ DPRINTF((output,"Thread[0x%x] called PR_NewTCPSocketPair\n",
+ PR_GetCurrentThread()));
+ PR_Close(pair[0]);
+ PR_Close(pair[1]);
+ break;
+
+ case 10:
+ PR_SetConcurrency(2);
+ DPRINTF((output,"Thread[0x%x] called PR_SetConcurrency\n",
+ PR_GetCurrentThread()));
+ break;
+
+ case 11:
+ PR_SetThreadPriority(PR_GetCurrentThread(), PR_PRIORITY_HIGH);
+ DPRINTF((output,"Thread[0x%x] called PR_SetThreadPriority\n",
+ PR_GetCurrentThread()));
+ break;
+
+ default:
+ break;
+ } /* switch() */
+ }
+} /* OneShot */
+
+int main(int argc, char **argv)
+{
+ PRStatus rv;
+ PRInt32 thread_cnt = DEFAULT_THREAD_COUNT;
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "dt:");
+
+#if defined(WIN32)
+ thread_provider = thread_win32;
+#elif defined(_PR_PTHREADS)
+ thread_provider = thread_pthread;
+#else
+ thread_provider = thread_nspr;
+#endif
+
+
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 'd': /* debug mode */
+ _debug_on = 1;
+ break;
+ case 't': /* thread count */
+ thread_cnt = atoi(opt->value);
+ break;
+ default:
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ PR_SetConcurrency(2);
+
+ output = PR_GetSpecialFD(PR_StandardOutput);
+
+ while (thread_cnt-- > 0)
+ {
+ rv = NSPRPUB_TESTS_CreateThread(OneShot, (void*)thread_cnt);
+ PR_ASSERT(PR_SUCCESS == rv);
+ PR_Sleep(PR_MillisecondsToInterval(5));
+ }
+ PR_Sleep(PR_SecondsToInterval(3));
+ return (PR_SUCCESS == PR_Cleanup()) ? 0 : 1;
+} /* main */
+
+/* foreign.c */
diff --git a/nsprpub/pr/tests/forktest.c b/nsprpub/pr/tests/forktest.c
new file mode 100644
index 0000000000..a6d4bc4bb4
--- /dev/null
+++ b/nsprpub/pr/tests/forktest.c
@@ -0,0 +1,254 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/***********************************************************************
+**
+** Name: forktest.c
+**
+** Description: UNIX test for fork functions.
+**
+** Modification History:
+** 15-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
+** The debug mode will print all of the printfs associated with this test.
+** The regress mode will be the default mode. Since the regress tool limits
+** the output to a one line status:PASS or FAIL,all of the printf statements
+** have been handled with an if (debug_mode) statement.
+** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to
+** recognize the return code from tha main program.
+** 12-June-97 AGarcic - Revert to return code 0 and 1, remove debug option (obsolete).
+***********************************************************************/
+
+/***********************************************************************
+** Includes
+***********************************************************************/
+/* Used to get the command line option */
+#include "plgetopt.h"
+
+#include "nspr.h"
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+PRIntn failed_already=0;
+
+#ifdef XP_UNIX
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <errno.h>
+
+static char *message = "Hello world!";
+
+static void
+ClientThreadFunc(void *arg)
+{
+ PRNetAddr addr;
+ PRFileDesc *sock = NULL;
+ PRInt32 tmp = (PRInt32)arg;
+
+ /*
+ * Make sure the PR_Accept call will block
+ */
+
+ printf("Wait one second before connect\n");
+ fflush(stdout);
+ PR_Sleep(PR_SecondsToInterval(1));
+
+ addr.inet.family = AF_INET;
+ addr.inet.ip = PR_htonl(INADDR_ANY);
+ addr.inet.port = 0;
+ if ((sock = PR_NewTCPSocket()) == NULL) {
+ fprintf(stderr, "failed to create TCP socket: error code %d\n",
+ PR_GetError());
+ failed_already = 1;
+ goto finish;
+ }
+ if (PR_Bind(sock, &addr) != PR_SUCCESS) {
+ fprintf(stderr, "PR_Bind failed: error code %d\n",
+ PR_GetError());
+ failed_already = 1;
+ goto finish;
+ }
+ addr.inet.ip = PR_htonl(INADDR_LOOPBACK);
+ addr.inet.port = PR_htons((PRInt16)tmp);
+ printf("Connecting to port %hu\n", PR_ntohs(addr.inet.port));
+ fflush(stdout);
+ if (PR_Connect(sock, &addr, PR_SecondsToInterval(5)) !=
+ PR_SUCCESS) {
+ fprintf(stderr, "PR_Connect failed: error code %d\n",
+ PR_GetError());
+ failed_already = 1;
+ goto finish;
+ }
+ printf("Writing message \"%s\"\n", message);
+ fflush(stdout);
+ if (PR_Send(sock, message, strlen(message) + 1, 0, PR_INTERVAL_NO_TIMEOUT) ==
+ -1) {
+ fprintf(stderr, "PR_Send failed: error code %d\n",
+ PR_GetError());
+ failed_already = 1;
+ goto finish;
+ }
+finish:
+ if (sock) {
+ PR_Close(sock);
+ }
+ return;
+}
+
+/*
+ * DoIO --
+ * This function creates a thread that acts as a client and itself.
+ * acts as a server. Then it joins the client thread.
+ */
+static void
+DoIO(void)
+{
+ PRThread *clientThread;
+ PRFileDesc *listenSock = NULL;
+ PRFileDesc *sock = NULL;
+ PRNetAddr addr;
+ PRInt32 nBytes;
+ char buf[128];
+
+ listenSock = PR_NewTCPSocket();
+ if (!listenSock) {
+ fprintf(stderr, "failed to create a TCP socket: error code %d\n",
+ PR_GetError());
+ failed_already = 1;
+ goto finish;
+ }
+ addr.inet.family = AF_INET;
+ addr.inet.ip = PR_htonl(INADDR_ANY);
+ addr.inet.port = 0;
+ if (PR_Bind(listenSock, &addr) == PR_FAILURE) {
+ fprintf(stderr, "failed to bind socket: error code %d\n",
+ PR_GetError());
+ failed_already = 1;
+ goto finish;
+ }
+ if (PR_GetSockName(listenSock, &addr) == PR_FAILURE) {
+ fprintf(stderr, "failed to get socket port number: error code %d\n",
+ PR_GetError());
+ failed_already = 1;
+ goto finish;
+ }
+ if (PR_Listen(listenSock, 5) == PR_FAILURE) {
+ fprintf(stderr, "PR_Listen failed: error code %d\n",
+ PR_GetError());
+ failed_already = 1;
+ goto finish;
+ }
+ clientThread = PR_CreateThread( PR_USER_THREAD, ClientThreadFunc,
+ (void *) PR_ntohs(addr.inet.port), PR_PRIORITY_NORMAL, PR_LOCAL_THREAD,
+ PR_JOINABLE_THREAD, 0);
+ if (clientThread == NULL) {
+ fprintf(stderr, "Cannot create client thread: (%d, %d)\n",
+ PR_GetError(), PR_GetOSError());
+ failed_already = 1;
+ goto finish;
+ }
+ printf("Accepting connection at port %hu\n", PR_ntohs(addr.inet.port));
+ fflush(stdout);
+ sock = PR_Accept(listenSock, &addr, PR_SecondsToInterval(5));
+ if (!sock) {
+ fprintf(stderr, "PR_Accept failed: error code %d\n",
+ PR_GetError());
+ failed_already = 1;
+ goto finish;
+ }
+ nBytes = PR_Recv(sock, buf, sizeof(buf), 0, PR_INTERVAL_NO_TIMEOUT);
+ if (nBytes == -1) {
+ fprintf(stderr, "PR_Recv failed: error code %d\n",
+ PR_GetError());
+ failed_already = 1;
+ goto finish;
+ }
+
+ /*
+ * Make sure it has proper null byte to mark end of string
+ */
+
+ buf[sizeof(buf) - 1] = '\0';
+ printf("Received \"%s\" from the client\n", buf);
+ fflush(stdout);
+ if (!strcmp(buf, message)) {
+ PR_JoinThread(clientThread);
+
+ printf("The message is received correctly\n");
+ fflush(stdout);
+ } else {
+ fprintf(stderr, "The message should be \"%s\"\n",
+ message);
+ failed_already = 1;
+ }
+
+finish:
+ if (listenSock) {
+ PR_Close(listenSock);
+ }
+ if (sock) {
+ PR_Close(sock);
+ }
+ return;
+}
+
+int main(int argc, char **argv)
+{
+ pid_t pid;
+
+ /* main test program */
+
+ DoIO();
+
+ pid = fork();
+
+ if (pid == (pid_t) -1) {
+ fprintf(stderr, "Fork failed: errno %d\n", errno);
+ failed_already=1;
+ return 1;
+ } else if (pid > 0) {
+ int childStatus;
+
+ printf("Fork succeeded. Parent process continues.\n");
+ DoIO();
+ if (waitpid(pid, &childStatus, 0) != pid) {
+ {
+ fprintf(stderr, "waitpid failed: %d\n", errno);
+ failed_already = 1;
+ }
+ } else if (!WIFEXITED(childStatus)
+ || WEXITSTATUS(childStatus) != 0) {
+ failed_already = 1;
+ }
+ printf("Parent process exits.\n");
+ if (!failed_already) {
+ printf("PASSED\n");
+ } else {
+ printf("FAILED\n");
+ }
+ return failed_already;
+ } else {
+ printf("Fork succeeded. Child process continues.\n");
+ DoIO();
+ printf("Child process exits.\n");
+ return failed_already;
+ }
+}
+
+#else /* XP_UNIX */
+
+int main( int argc,
+ char *argv[]
+ )
+{
+
+ printf("The fork test is applicable to Unix only.\n");
+ return 0;
+
+}
+
+#endif /* XP_UNIX */
diff --git a/nsprpub/pr/tests/formattm.c b/nsprpub/pr/tests/formattm.c
new file mode 100644
index 0000000000..63355b28b7
--- /dev/null
+++ b/nsprpub/pr/tests/formattm.c
@@ -0,0 +1,50 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* A test program for PR_FormatTime and PR_FormatTimeUSEnglish */
+
+#include "prtime.h"
+
+#include <stdio.h>
+
+int main(int argc, char **argv)
+{
+ char buffer[256];
+ char small_buffer[8];
+ PRTime now;
+ PRExplodedTime tod;
+
+ now = PR_Now();
+ PR_ExplodeTime(now, PR_LocalTimeParameters, &tod);
+
+ if (PR_FormatTime(buffer, sizeof(buffer),
+ "%a %b %d %H:%M:%S %Z %Y", &tod) != 0) {
+ printf("%s\n", buffer);
+ } else {
+ fprintf(stderr, "PR_FormatTime(buffer) failed\n");
+ return 1;
+ }
+
+ small_buffer[0] = '?';
+ if (PR_FormatTime(small_buffer, sizeof(small_buffer),
+ "%a %b %d %H:%M:%S %Z %Y", &tod) == 0) {
+ if (small_buffer[0] != '\0') {
+ fprintf(stderr, "PR_FormatTime(small_buffer) did not output "
+ "an empty string on failure\n");
+ return 1;
+ }
+ printf("%s\n", small_buffer);
+ } else {
+ fprintf(stderr, "PR_FormatTime(small_buffer) succeeded "
+ "unexpectedly\n");
+ return 1;
+ }
+
+ (void)PR_FormatTimeUSEnglish(buffer, sizeof(buffer),
+ "%a %b %d %H:%M:%S %Z %Y", &tod);
+ printf("%s\n", buffer);
+
+ return 0;
+}
diff --git a/nsprpub/pr/tests/freeif.c b/nsprpub/pr/tests/freeif.c
new file mode 100644
index 0000000000..1d38d0e31a
--- /dev/null
+++ b/nsprpub/pr/tests/freeif.c
@@ -0,0 +1,47 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * A test to see if the macros PR_DELETE and PR_FREEIF are
+ * properly defined. (See Bugzilla bug #39110.)
+ */
+
+#include "nspr.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+static void Noop(void) { }
+
+static void Fail(void)
+{
+ printf("FAIL\n");
+ exit(1);
+}
+
+int main(int argc, char **argv)
+{
+ int foo = 1;
+ char *ptr = NULL;
+
+ /* this fails to compile with the old definition of PR_DELETE */
+ if (foo) {
+ PR_DELETE(ptr);
+ }
+ else {
+ Noop();
+ }
+
+ /* this nests incorrectly with the old definition of PR_FREEIF */
+ if (foo) {
+ PR_FREEIF(ptr);
+ }
+ else {
+ Fail();
+ }
+
+ printf("PASS\n");
+ return 0;
+}
diff --git a/nsprpub/pr/tests/fsync.c b/nsprpub/pr/tests/fsync.c
new file mode 100644
index 0000000000..3e0fb175c1
--- /dev/null
+++ b/nsprpub/pr/tests/fsync.c
@@ -0,0 +1,130 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "prio.h"
+#include "prmem.h"
+#include "prprf.h"
+#include "prinrval.h"
+
+#include "plerror.h"
+#include "plgetopt.h"
+
+static PRFileDesc *err = NULL;
+
+static void Help(void)
+{
+ PR_fprintf(err, "Usage: [-S] [-K <n>] [-h] <filename>\n");
+ PR_fprintf(err, "\t-c Nuber of iterations (default: 10)\n");
+ PR_fprintf(err, "\t-S Sync the file (default: FALSE)\n");
+ PR_fprintf(err, "\t-K Size of file (K bytes) (default: 10)\n");
+ PR_fprintf(err, "\t Name of file to write (default: ./tmp-sync.dat)\n");
+ PR_fprintf(err, "\t-h This message and nothing else\n");
+} /* Help */
+
+int main(int argc, char **argv)
+{
+ PRStatus rv;
+ PLOptStatus os;
+ PRUint8 *buffer;
+ PRFileDesc *file = NULL;
+ const char *filename = "sync.dat";
+ PRUint32 index, loops, iterations = 10, filesize = 10;
+ PRIntn flags = PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "hSK:c:");
+ PRIntervalTime time, total = 0, shortest = 0x7fffffff, longest = 0;
+
+ err = PR_GetSpecialFD(PR_StandardError);
+
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 0: /* Name of file to create */
+ filename = opt->value;
+ break;
+ case 'S': /* Use sych option on file */
+ flags |= PR_SYNC;
+ break;
+ case 'K': /* Size of file to write */
+ filesize = atoi(opt->value);
+ break;
+ case 'c': /* Number of iterations */
+ iterations = atoi(opt->value);
+ break;
+ case 'h': /* user wants some guidance */
+ default: /* user needs some guidance */
+ Help(); /* so give him an earful */
+ return 2; /* but not a lot else */
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ file = PR_Open(filename, flags, 0666);
+ if (NULL == file)
+ {
+ PL_FPrintError(err, "Failed to open file");
+ return 1;
+ }
+
+ buffer = (PRUint8*)PR_CALLOC(1024);
+ if (NULL == buffer)
+ {
+ PL_FPrintError(err, "Cannot allocate buffer");
+ return 1;
+ }
+
+ for (index = 0; index < sizeof(buffer); ++index) {
+ buffer[index] = (PRUint8)index;
+ }
+
+ for (loops = 0; loops < iterations; ++loops)
+ {
+ time = PR_IntervalNow();
+ for (index = 0; index < filesize; ++index)
+ {
+ PR_Write(file, buffer, 1024);
+ }
+ time = (PR_IntervalNow() - time);
+
+ total += time;
+ if (time < shortest) {
+ shortest = time;
+ }
+ else if (time > longest) {
+ longest = time;
+ }
+ if (0 != PR_Seek(file, 0, PR_SEEK_SET))
+ {
+ PL_FPrintError(err, "Rewinding file");
+ return 1;
+ }
+ }
+
+ total = total / iterations;
+ PR_fprintf(
+ err, "%u iterations over a %u kbyte %sfile: %u [%u] %u\n",
+ iterations, filesize, ((flags & PR_SYNC) ? "SYNCH'd " : ""),
+ PR_IntervalToMicroseconds(shortest),
+ PR_IntervalToMicroseconds(total),
+ PR_IntervalToMicroseconds(longest));
+
+ PR_DELETE(buffer);
+ rv = PR_Close(file);
+ if (PR_SUCCESS != rv)
+ {
+ PL_FPrintError(err, "Closing file failed");
+ return 1;
+ }
+ rv = PR_Delete(filename);
+ if (PR_SUCCESS != rv)
+ {
+ PL_FPrintError(err, "Deleting file failed");
+ return 1;
+ }
+ return 0;
+}
diff --git a/nsprpub/pr/tests/getai.c b/nsprpub/pr/tests/getai.c
new file mode 100644
index 0000000000..d759ed827d
--- /dev/null
+++ b/nsprpub/pr/tests/getai.c
@@ -0,0 +1,32 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nspr.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc, char **argv)
+{
+ PRAddrInfo *ai;
+ void *iter;
+ PRNetAddr addr;
+
+ ai = PR_GetAddrInfoByName(argv[1], PR_AF_UNSPEC, PR_AI_ADDRCONFIG);
+ if (ai == NULL) {
+ fprintf(stderr, "PR_GetAddrInfoByName failed: (%d, %d)\n",
+ PR_GetError(), PR_GetOSError());
+ exit(1);
+ }
+ printf("%s\n", PR_GetCanonNameFromAddrInfo(ai));
+ iter = NULL;
+ while ((iter = PR_EnumerateAddrInfo(iter, ai, 0, &addr)) != NULL) {
+ char buf[128];
+ PR_NetAddrToString(&addr, buf, sizeof buf);
+ printf("%s\n", buf);
+ }
+ PR_FreeAddrInfo(ai);
+ return 0;
+}
diff --git a/nsprpub/pr/tests/gethost.c b/nsprpub/pr/tests/gethost.c
new file mode 100644
index 0000000000..71704a8454
--- /dev/null
+++ b/nsprpub/pr/tests/gethost.c
@@ -0,0 +1,267 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * 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 "mozilla.org"
+
+static void Help(void)
+{
+ fprintf(stderr, "Usage: gethost [-h] [hostname]\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, "h");
+
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option) {
+ 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);
+ 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);
+ idx = 0;
+ printf("PR_GetHostByAddr with PR_AF_INET6\n");
+ 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_GetHostByAddr with PR_AF_INET6 done\n");
+
+ PR_StringToNetAddr("::1", &addr);
+ if (PR_IsNetAddrType(&addr, PR_IpAddrV4Mapped) == PR_TRUE) {
+ fprintf(stderr, "addr should not be ipv4 mapped address\n");
+ exit(1);
+ }
+ if (PR_IsNetAddrType(&addr, PR_IpAddrLoopback) == PR_FALSE) {
+ fprintf(stderr, "addr should be loopback address\n");
+ exit(1);
+ }
+
+ PR_StringToNetAddr("127.0.0.1", &addr);
+ if (PR_IsNetAddrType(&addr, PR_IpAddrLoopback) == PR_FALSE) {
+ fprintf(stderr, "addr should be loopback address\n");
+ exit(1);
+ }
+ PR_StringToNetAddr("::FFFF:127.0.0.1", &addr);
+ if (PR_IsNetAddrType(&addr, PR_IpAddrV4Mapped) == PR_FALSE) {
+ fprintf(stderr, "addr should be ipv4 mapped address\n");
+ exit(1);
+ }
+ if (PR_IsNetAddrType(&addr, PR_IpAddrLoopback) == PR_FALSE) {
+ fprintf(stderr, "addr should be loopback address\n");
+ exit(1);
+ }
+
+ 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);
+ }
+ {
+ char buf[256];
+ PR_NetAddrToString(&addr, buf, 256);
+ printf("IPv4 INADDRANY: %s\n", buf);
+ }
+ 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);
+ }
+ {
+ char buf[256];
+ PR_NetAddrToString(&addr, buf, 256);
+ printf("IPv4 LOOPBACK: %s\n", buf);
+ }
+
+ 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);
+ }
+ {
+ char buf[256];
+ PR_NetAddrToString(&addr, buf, 256);
+ printf("IPv6 INADDRANY: %s\n", buf);
+ }
+ 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);
+ }
+ {
+ char buf[256];
+ PR_NetAddrToString(&addr, buf, 256);
+ printf("IPv6 LOOPBACK: %s\n", buf);
+ }
+ {
+ PRIPv6Addr v6addr;
+ char tmp_buf[256];
+
+ PR_SetNetAddr(PR_IpAddrLoopback, PR_AF_INET, 0, &addr);
+
+ PR_ConvertIPv4AddrToIPv6(addr.inet.ip, &v6addr);
+ PR_SetNetAddr(PR_IpAddrAny, PR_AF_INET6, 0, &addr);
+ addr.ipv6.ip = v6addr;
+ PR_NetAddrToString(&addr, tmp_buf, 256);
+ printf("IPv4-mapped IPv6 LOOPBACK: %s\n", tmp_buf);
+ }
+ printf("PASS\n");
+ return 0;
+}
diff --git a/nsprpub/pr/tests/getproto.c b/nsprpub/pr/tests/getproto.c
new file mode 100644
index 0000000000..1a33b1f256
--- /dev/null
+++ b/nsprpub/pr/tests/getproto.c
@@ -0,0 +1,90 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ *************************************************************************
+ *
+ * File: getproto.c
+ *
+ * A test program for PR_GetProtoByName and PR_GetProtoByNumber
+ *
+ *************************************************************************
+ */
+
+#include "plstr.h"
+#include "plerror.h"
+#include "prinit.h"
+#include "prprf.h"
+#include "prnetdb.h"
+#include "prerror.h"
+
+int main(int argc, char **argv)
+{
+ PRFileDesc *prstderr = PR_GetSpecialFD(PR_StandardError);
+ PRBool failed = PR_FALSE;
+ PRProtoEnt proto;
+ char buf[2048];
+ PRStatus rv;
+
+ PR_STDIO_INIT();
+ rv = PR_GetProtoByName("tcp", buf, sizeof(buf), &proto);
+ if (PR_FAILURE == rv) {
+ failed = PR_TRUE;
+ PL_FPrintError(prstderr, "PR_GetProtoByName failed");
+ }
+ else if (6 != proto.p_num) {
+ PR_fprintf(
+ prstderr,"tcp is usually 6, but is %d on this machine\n",
+ proto.p_num);
+ }
+ else {
+ PR_fprintf(prstderr, "tcp is protocol number %d\n", proto.p_num);
+ }
+
+ rv = PR_GetProtoByName("udp", buf, sizeof(buf), &proto);
+ if (PR_FAILURE == rv) {
+ failed = PR_TRUE;
+ PL_FPrintError(prstderr, "PR_GetProtoByName failed");
+ }
+ else if (17 != proto.p_num) {
+ PR_fprintf(
+ prstderr, "udp is usually 17, but is %d on this machine\n",
+ proto.p_num);
+ }
+ else {
+ PR_fprintf(prstderr, "udp is protocol number %d\n", proto.p_num);
+ }
+
+ rv = PR_GetProtoByNumber(6, buf, sizeof(buf), &proto);
+ if (PR_FAILURE == rv) {
+ failed = PR_TRUE;
+ PL_FPrintError(prstderr, "PR_GetProtoByNumber failed");
+ }
+ else if (PL_strcmp("tcp", proto.p_name)) {
+ PR_fprintf(
+ prstderr, "Protocol number 6 is usually tcp, but is %s"
+ " on this platform\n", proto.p_name);
+ }
+ else {
+ PR_fprintf(prstderr, "Protocol number 6 is %s\n", proto.p_name);
+ }
+
+ rv = PR_GetProtoByNumber(17, buf, sizeof(buf), &proto);
+ if (PR_FAILURE == rv) {
+ failed = PR_TRUE;
+ PL_FPrintError(prstderr, "PR_GetProtoByNumber failed");
+ }
+ else if (PL_strcmp("udp", proto.p_name)) {
+ PR_fprintf(
+ prstderr, "Protocol number 17 is usually udp, but is %s"
+ " on this platform\n", proto.p_name);
+ }
+ else {
+ PR_fprintf(prstderr, "Protocol number 17 is %s\n", proto.p_name);
+ }
+
+ PR_fprintf(prstderr, (failed) ? "FAILED\n" : "PASSED\n");
+ return (failed) ? 1 : 0;
+}
diff --git a/nsprpub/pr/tests/i2l.c b/nsprpub/pr/tests/i2l.c
new file mode 100644
index 0000000000..a28cd16a80
--- /dev/null
+++ b/nsprpub/pr/tests/i2l.c
@@ -0,0 +1,103 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include <stdlib.h>
+
+#include "prio.h"
+#include "prinit.h"
+#include "prprf.h"
+#include "prlong.h"
+
+#include "plerror.h"
+#include "plgetopt.h"
+
+typedef union Overlay_i
+{
+ PRInt32 i;
+ PRInt64 l;
+} Overlay_i;
+
+typedef union Overlay_u
+{
+ PRUint32 i;
+ PRUint64 l;
+} Overlay_u;
+
+static PRFileDesc *err = NULL;
+
+static void Help(void)
+{
+ PR_fprintf(err, "Usage: -i n | -u n | -h\n");
+ PR_fprintf(err, "\t-i n treat following number as signed integer\n");
+ PR_fprintf(err, "\t-u n treat following number as unsigned integer\n");
+ PR_fprintf(err, "\t-h This message and nothing else\n");
+} /* Help */
+
+static PRIntn PR_CALLBACK RealMain(PRIntn argc, char **argv)
+{
+ Overlay_i si;
+ Overlay_u ui;
+ PLOptStatus os;
+ PRBool bsi = PR_FALSE, bui = PR_FALSE;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "hi:u:");
+ err = PR_GetSpecialFD(PR_StandardError);
+
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 'i': /* signed integer */
+ si.i = (PRInt32)atoi(opt->value);
+ bsi = PR_TRUE;
+ break;
+ case 'u': /* unsigned */
+ ui.i = (PRUint32)atoi(opt->value);
+ bui = PR_TRUE;
+ break;
+ case 'h': /* user wants some guidance */
+ default:
+ Help(); /* so give him an earful */
+ return 2; /* but not a lot else */
+ }
+ }
+ PL_DestroyOptState(opt);
+
+#if defined(HAVE_LONG_LONG)
+ PR_fprintf(err, "We have long long\n");
+#else
+ PR_fprintf(err, "We don't have long long\n");
+#endif
+
+ if (bsi)
+ {
+ PR_fprintf(err, "Converting %ld: ", si.i);
+ LL_I2L(si.l, si.i);
+ PR_fprintf(err, "%lld\n", si.l);
+ }
+
+ if (bui)
+ {
+ PR_fprintf(err, "Converting %lu: ", ui.i);
+ LL_I2L(ui.l, ui.i);
+ PR_fprintf(err, "%llu\n", ui.l);
+ }
+ return 0;
+
+} /* main */
+
+
+int main(int argc, char **argv)
+{
+ PRIntn rv;
+
+ PR_STDIO_INIT();
+ rv = PR_Initialize(RealMain, argc, argv, 0);
+ return rv;
+} /* main */
+
+/* i2l.c */
diff --git a/nsprpub/pr/tests/initclk.c b/nsprpub/pr/tests/initclk.c
new file mode 100644
index 0000000000..65d8b17e71
--- /dev/null
+++ b/nsprpub/pr/tests/initclk.c
@@ -0,0 +1,77 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * This is a regression test for the bug that the interval timer
+ * is not initialized when _PR_CreateCPU calls PR_IntervalNow.
+ * The bug would make this test program finish prematurely,
+ * when the SHORT_TIMEOUT period expires. The correct behavior
+ * is for the test to finish when the LONG_TIMEOUT period expires.
+ */
+
+#include "prlock.h"
+#include "prcvar.h"
+#include "prthread.h"
+#include "prinrval.h"
+#include "prlog.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+/* The timeouts, in milliseconds */
+#define SHORT_TIMEOUT 1000
+#define LONG_TIMEOUT 3000
+
+PRLock *lock1, *lock2;
+PRCondVar *cv1, *cv2;
+
+void ThreadFunc(void *arg)
+{
+ PR_Lock(lock1);
+ PR_WaitCondVar(cv1, PR_MillisecondsToInterval(SHORT_TIMEOUT));
+ PR_Unlock(lock1);
+}
+
+int main(int argc, char **argv)
+{
+ PRThread *thread;
+ PRIntervalTime start, end;
+ PRUint32 elapsed_ms;
+
+ lock1 = PR_NewLock();
+ PR_ASSERT(NULL != lock1);
+ cv1 = PR_NewCondVar(lock1);
+ PR_ASSERT(NULL != cv1);
+ lock2 = PR_NewLock();
+ PR_ASSERT(NULL != lock2);
+ cv2 = PR_NewCondVar(lock2);
+ PR_ASSERT(NULL != cv2);
+ start = PR_IntervalNow();
+ thread = PR_CreateThread(
+ PR_USER_THREAD,
+ ThreadFunc,
+ NULL,
+ PR_PRIORITY_NORMAL,
+ PR_LOCAL_THREAD,
+ PR_JOINABLE_THREAD,
+ 0);
+ PR_ASSERT(NULL != thread);
+ PR_Lock(lock2);
+ PR_WaitCondVar(cv2, PR_MillisecondsToInterval(LONG_TIMEOUT));
+ PR_Unlock(lock2);
+ PR_JoinThread(thread);
+ end = PR_IntervalNow();
+ elapsed_ms = PR_IntervalToMilliseconds((PRIntervalTime)(end - start));
+ /* Allow 100ms imprecision */
+ if (elapsed_ms < LONG_TIMEOUT - 100 || elapsed_ms > LONG_TIMEOUT + 100) {
+ printf("Elapsed time should be %u ms but is %u ms\n",
+ LONG_TIMEOUT, elapsed_ms);
+ printf("FAIL\n");
+ exit(1);
+ }
+ printf("Elapsed time: %u ms, expected time: %u ms\n",
+ LONG_TIMEOUT, elapsed_ms);
+ printf("PASS\n");
+ return 0;
+}
diff --git a/nsprpub/pr/tests/inrval.c b/nsprpub/pr/tests/inrval.c
new file mode 100644
index 0000000000..52f7b71da1
--- /dev/null
+++ b/nsprpub/pr/tests/inrval.c
@@ -0,0 +1,217 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+** file: inrval.c
+** description: Interval conversion test.
+** Modification History:
+** 15-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
+** The debug mode will print all of the printfs associated with this test.
+** The regress mode will be the default mode. Since the regress tool limits
+** the output to a one line status:PASS or FAIL,all of the printf statements
+** have been handled with an if (debug_mode) statement.
+** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to
+** recognize the return code from tha main program.
+**/
+/***********************************************************************
+** Includes
+***********************************************************************/
+/* Used to get the command line option */
+#include "plgetopt.h"
+
+#include "prinit.h"
+#include "obsolete/pralarm.h"
+
+#include "prio.h"
+#include "prprf.h"
+#include "prlock.h"
+#include "prlong.h"
+#include "prcvar.h"
+#include "prinrval.h"
+#include "prtime.h"
+
+#include "plgetopt.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+static PRIntn debug_mode;
+static PRFileDesc *output;
+
+
+static void TestConversions(void)
+{
+ PRIntervalTime ticks = PR_TicksPerSecond();
+
+ if (debug_mode) {
+ PR_fprintf(output, "PR_TicksPerSecond: %ld\n\n", ticks);
+ PR_fprintf(output, "PR_SecondsToInterval(1): %ld\n", PR_SecondsToInterval(1));
+ PR_fprintf(output, "PR_MillisecondsToInterval(1000): %ld\n", PR_MillisecondsToInterval(1000));
+ PR_fprintf(output, "PR_MicrosecondsToInterval(1000000): %ld\n\n", PR_MicrosecondsToInterval(1000000));
+
+ PR_fprintf(output, "PR_SecondsToInterval(3): %ld\n", PR_SecondsToInterval(3));
+ PR_fprintf(output, "PR_MillisecondsToInterval(3000): %ld\n", PR_MillisecondsToInterval(3000));
+ PR_fprintf(output, "PR_MicrosecondsToInterval(3000000): %ld\n\n", PR_MicrosecondsToInterval(3000000));
+
+ PR_fprintf(output, "PR_IntervalToSeconds(%ld): %ld\n", ticks, PR_IntervalToSeconds(ticks));
+ PR_fprintf(output, "PR_IntervalToMilliseconds(%ld): %ld\n", ticks, PR_IntervalToMilliseconds(ticks));
+ PR_fprintf(output, "PR_IntervalToMicroseconds(%ld): %ld\n\n", ticks, PR_IntervalToMicroseconds(ticks));
+
+ ticks *= 3;
+ PR_fprintf(output, "PR_IntervalToSeconds(%ld): %ld\n", ticks, PR_IntervalToSeconds(ticks));
+ PR_fprintf(output, "PR_IntervalToMilliseconds(%ld): %ld\n", ticks, PR_IntervalToMilliseconds(ticks));
+ PR_fprintf(output, "PR_IntervalToMicroseconds(%ld): %ld\n\n", ticks, PR_IntervalToMicroseconds(ticks));
+ } /*end debug mode */
+} /* TestConversions */
+
+static void TestIntervalOverhead(void)
+{
+ /* Hopefully the optimizer won't delete this function */
+ PRUint32 elapsed, per_call, loops = 1000000;
+
+ PRIntervalTime timeout, timein = PR_IntervalNow();
+ while (--loops > 0) {
+ timeout = PR_IntervalNow();
+ }
+
+ elapsed = 1000U * PR_IntervalToMicroseconds(timeout - timein);
+ per_call = elapsed / 1000000U;
+ PR_fprintf(
+ output, "Overhead of 'PR_IntervalNow()' is %u nsecs\n\n", per_call);
+} /* TestIntervalOverhead */
+
+static void TestNowOverhead(void)
+{
+ PRTime timeout, timein;
+ PRInt32 overhead, loops = 1000000;
+ PRInt64 elapsed, per_call, ten23rd, ten26th;
+
+ LL_I2L(ten23rd, 1000);
+ LL_I2L(ten26th, 1000000);
+
+ timein = PR_Now();
+ while (--loops > 0) {
+ timeout = PR_Now();
+ }
+
+ LL_SUB(elapsed, timeout, timein);
+ LL_MUL(elapsed, elapsed, ten23rd);
+ LL_DIV(per_call, elapsed, ten26th);
+ LL_L2I(overhead, per_call);
+ PR_fprintf(
+ output, "Overhead of 'PR_Now()' is %u nsecs\n\n", overhead);
+} /* TestNowOverhead */
+
+static void TestIntervals(void)
+{
+ PRStatus rv;
+ PRUint32 delta;
+ PRInt32 seconds;
+ PRUint64 elapsed, thousand;
+ PRTime timein, timeout;
+ PRLock *ml = PR_NewLock();
+ PRCondVar *cv = PR_NewCondVar(ml);
+ for (seconds = 0; seconds < 10; ++seconds)
+ {
+ PRIntervalTime ticks = PR_SecondsToInterval(seconds);
+ PR_Lock(ml);
+ timein = PR_Now();
+ rv = PR_WaitCondVar(cv, ticks);
+ timeout = PR_Now();
+ PR_Unlock(ml);
+ LL_SUB(elapsed, timeout, timein);
+ LL_I2L(thousand, 1000);
+ LL_DIV(elapsed, elapsed, thousand);
+ LL_L2UI(delta, elapsed);
+ if (debug_mode) PR_fprintf(output,
+ "TestIntervals: %swaiting %ld seconds took %ld msecs\n",
+ ((rv == PR_SUCCESS) ? "" : "FAILED "), seconds, delta);
+ }
+ PR_DestroyCondVar(cv);
+ PR_DestroyLock(ml);
+ if (debug_mode) {
+ PR_fprintf(output, "\n");
+ }
+} /* TestIntervals */
+
+static PRIntn PR_CALLBACK RealMain(int argc, char** argv)
+{
+ PRUint32 vcpu, cpus = 0, loops = 1000;
+
+ /* The command line argument: -d is used to determine if the test is being run
+ in debug mode. The regress tool requires only one line output:PASS or FAIL.
+ All of the printfs associated with this test has been handled with a if (debug_mode)
+ test.
+ Usage: test_name -d
+ */
+
+ /* main test */
+
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "dl:c:");
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 'd': /* debug mode */
+ debug_mode = 1;
+ break;
+ case 'c': /* concurrency counter */
+ cpus = atoi(opt->value);
+ break;
+ case 'l': /* loop counter */
+ loops = atoi(opt->value);
+ break;
+ default:
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ output = PR_GetSpecialFD(PR_StandardOutput);
+ PR_fprintf(output, "inrval: Examine stdout to determine results.\n");
+
+ if (cpus == 0) {
+ cpus = 8;
+ }
+ if (loops == 0) {
+ loops = 1000;
+ }
+
+ if (debug_mode > 0)
+ {
+ PR_fprintf(output, "Inrval: Using %d loops\n", loops);
+ PR_fprintf(output, "Inrval: Using 1 and %d cpu(s)\n", cpus);
+ }
+
+ for (vcpu = 1; vcpu <= cpus; vcpu += cpus - 1)
+ {
+ if (debug_mode) {
+ PR_fprintf(output, "\nInrval: Using %d CPU(s)\n\n", vcpu);
+ }
+ PR_SetConcurrency(vcpu);
+
+ TestNowOverhead();
+ TestIntervalOverhead();
+ TestConversions();
+ TestIntervals();
+ }
+
+ return 0;
+}
+
+
+int main(int argc, char **argv)
+{
+ PRIntn rv;
+
+ PR_STDIO_INIT();
+ rv = PR_Initialize(RealMain, argc, argv, 0);
+ return rv;
+} /* main */
+
diff --git a/nsprpub/pr/tests/instrumt.c b/nsprpub/pr/tests/instrumt.c
new file mode 100644
index 0000000000..e1ca94d035
--- /dev/null
+++ b/nsprpub/pr/tests/instrumt.c
@@ -0,0 +1,478 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+** File: instrumt.c
+** Description: This test is for the NSPR debug aids defined in
+** prcountr.h, prtrace.h, prolock.h
+**
+** The test case tests the three debug aids in NSPR:
+**
+** Diagnostic messages can be enabled using "instrumt -v 6"
+** This sets the msgLevel to something that PR_LOG() likes.
+** Also define in the environment "NSPR_LOG_MODULES=Test:6"
+**
+** CounterTest() tests the counter facility. This test
+** creates 4 threads. Each thread either increments, decrements,
+** adds to or subtracts from a counter, depending on an argument
+** passed to the thread at thread-create time. Each of these threads
+** does COUNT_LIMIT iterations doing its thing. When all 4 threads
+** are done, the result of the counter is evaluated. If all was atomic,
+** the the value of the counter should be zero.
+**
+** TraceTest():
+** This test mingles with the counter test. Counters trace.
+** A thread to extract trace entries on the fly is started.
+** A thread to dump trace entries to a file is started.
+**
+** OrderedLockTest():
+**
+**
+**
+**
+**
+*/
+
+#include <stdio.h>
+#include <plstr.h>
+#include <prclist.h>
+#include <prmem.h>
+#include <plgetopt.h>
+#include <prlog.h>
+#include <prmon.h>
+#include <pratom.h>
+#include <prtrace.h>
+#include <prcountr.h>
+#include <prolock.h>
+
+#define COUNT_LIMIT (10 * ( 1024))
+
+#define SMALL_TRACE_BUFSIZE ( 60 * 1024 )
+
+typedef enum
+{
+ CountLoop = 1,
+ TraceLoop = 2,
+ TraceFlow = 3
+} TraceTypes;
+
+
+PRLogModuleLevel msgLevel = PR_LOG_ALWAYS;
+
+PRBool help = PR_FALSE;
+PRBool failed = PR_FALSE;
+
+
+PRLogModuleInfo *lm;
+PRMonitor *mon;
+PRInt32 activeThreads = 0;
+PR_DEFINE_COUNTER( hCounter );
+PR_DEFINE_TRACE( hTrace );
+
+static void Help(void)
+{
+ printf("Help? ... Ha!\n");
+}
+
+static void ListCounters(void)
+{
+ PR_DEFINE_COUNTER( qh );
+ PR_DEFINE_COUNTER( rh );
+ const char *qn, *rn, *dn;
+ const char **qname = &qn, **rname = &rn, **desc = &dn;
+ PRUint32 tCtr;
+
+ PR_INIT_COUNTER_HANDLE( qh, NULL );
+ PR_FIND_NEXT_COUNTER_QNAME(qh, qh );
+ while ( qh != NULL )
+ {
+ PR_INIT_COUNTER_HANDLE( rh, NULL );
+ PR_FIND_NEXT_COUNTER_RNAME(rh, rh, qh );
+ while ( rh != NULL )
+ {
+ PR_GET_COUNTER_NAME_FROM_HANDLE( rh, qname, rname, desc );
+ PR_GET_COUNTER(tCtr, rh);
+ PR_LOG( lm, msgLevel,
+ ( "QName: %s RName: %s Desc: %s Value: %ld\n",
+ qn, rn, dn, tCtr ));
+ PR_FIND_NEXT_COUNTER_RNAME(rh, rh, qh );
+ }
+ PR_FIND_NEXT_COUNTER_QNAME(qh, qh);
+ }
+ return;
+} /* end ListCounters() */
+
+static void ListTraces(void)
+{
+ PR_DEFINE_TRACE( qh );
+ PR_DEFINE_TRACE( rh );
+ const char *qn, *rn, *dn;
+ const char **qname = &qn, **rname = &rn, **desc = &dn;
+
+ PR_INIT_TRACE_HANDLE( qh, NULL );
+ PR_FIND_NEXT_TRACE_QNAME(qh, qh );
+ while ( qh != NULL )
+ {
+ PR_INIT_TRACE_HANDLE( rh, NULL );
+ PR_FIND_NEXT_TRACE_RNAME(rh, rh, qh );
+ while ( rh != NULL )
+ {
+ PR_GET_TRACE_NAME_FROM_HANDLE( rh, qname, rname, desc );
+ PR_LOG( lm, msgLevel,
+ ( "QName: %s RName: %s Desc: %s",
+ qn, rn, dn ));
+ PR_FIND_NEXT_TRACE_RNAME(rh, rh, qh );
+ }
+ PR_FIND_NEXT_TRACE_QNAME(qh, qh);
+ }
+ return;
+} /* end ListCounters() */
+
+
+static PRInt32 one = 1;
+static PRInt32 two = 2;
+static PRInt32 three = 3;
+static PRInt32 four = 4;
+
+/*
+** Thread to iteratively count something.
+*/
+static void PR_CALLBACK CountSomething( void *arg )
+{
+ PRInt32 switchVar = *((PRInt32 *)arg);
+ PRInt32 i;
+
+ PR_LOG( lm, msgLevel,
+ ("CountSomething: begin thread %ld", switchVar ));
+
+ for ( i = 0; i < COUNT_LIMIT ; i++)
+ {
+ switch ( switchVar )
+ {
+ case 1 :
+ PR_INCREMENT_COUNTER( hCounter );
+ break;
+ case 2 :
+ PR_DECREMENT_COUNTER( hCounter );
+ break;
+ case 3 :
+ PR_ADD_TO_COUNTER( hCounter, 1 );
+ break;
+ case 4 :
+ PR_SUBTRACT_FROM_COUNTER( hCounter, 1 );
+ break;
+ default :
+ PR_ASSERT( 0 );
+ break;
+ }
+ PR_TRACE( hTrace, CountLoop, switchVar, i, 0, 0, 0, 0, 0 );
+ } /* end for() */
+
+ PR_LOG( lm, msgLevel,
+ ("CounterSomething: end thread %ld", switchVar ));
+
+ PR_EnterMonitor(mon);
+ --activeThreads;
+ PR_Notify( mon );
+ PR_ExitMonitor(mon);
+
+ return;
+} /* end CountSomething() */
+
+/*
+** Create the counter threads.
+*/
+static void CounterTest( void )
+{
+ PRThread *t1, *t2, *t3, *t4;
+ PRIntn i = 0;
+ PR_DEFINE_COUNTER( tc );
+ PR_DEFINE_COUNTER( zCounter );
+
+ PR_LOG( lm, msgLevel,
+ ("Begin CounterTest"));
+
+ /*
+ ** Test Get and Set of a counter.
+ **
+ */
+ PR_CREATE_COUNTER( zCounter, "Atomic", "get/set test", "test get and set of counter" );
+ PR_SET_COUNTER( zCounter, 9 );
+ PR_GET_COUNTER( i, zCounter );
+ if ( i != 9 )
+ {
+ failed = PR_TRUE;
+ PR_LOG( lm, msgLevel,
+ ("Counter set/get failed"));
+ }
+
+ activeThreads += 4;
+ PR_CREATE_COUNTER( hCounter, "Atomic", "SMP Tests", "test atomic nature of counter" );
+
+ PR_GET_COUNTER_HANDLE_FROM_NAME( tc, "Atomic", "SMP Tests" );
+ PR_ASSERT( tc == hCounter );
+
+ t1 = PR_CreateThread(PR_USER_THREAD,
+ CountSomething, &one,
+ PR_PRIORITY_NORMAL,
+ PR_GLOBAL_THREAD,
+ PR_UNJOINABLE_THREAD,
+ 0);
+ PR_ASSERT(t1);
+
+ t2 = PR_CreateThread(PR_USER_THREAD,
+ CountSomething, &two,
+ PR_PRIORITY_NORMAL,
+ PR_GLOBAL_THREAD,
+ PR_UNJOINABLE_THREAD,
+ 0);
+ PR_ASSERT(t2);
+
+ t3 = PR_CreateThread(PR_USER_THREAD,
+ CountSomething, &three,
+ PR_PRIORITY_NORMAL,
+ PR_GLOBAL_THREAD,
+ PR_UNJOINABLE_THREAD,
+ 0);
+ PR_ASSERT(t3);
+
+ t4 = PR_CreateThread(PR_USER_THREAD,
+ CountSomething, &four,
+ PR_PRIORITY_NORMAL,
+ PR_GLOBAL_THREAD,
+ PR_UNJOINABLE_THREAD,
+ 0);
+ PR_ASSERT(t4);
+
+ PR_LOG( lm, msgLevel,
+ ("Counter Threads started"));
+
+ ListCounters();
+ return;
+} /* end CounterTest() */
+
+/*
+** Thread to dump trace buffer to a file.
+*/
+static void PR_CALLBACK RecordTrace(void *arg )
+{
+ PR_RECORD_TRACE_ENTRIES();
+
+ PR_EnterMonitor(mon);
+ --activeThreads;
+ PR_Notify( mon );
+ PR_ExitMonitor(mon);
+
+ return;
+} /* end RecordTrace() */
+
+
+
+#define NUM_TRACE_RECORDS ( 10000 )
+/*
+** Thread to extract and print trace entries from the buffer.
+*/
+static void PR_CALLBACK SampleTrace( void *arg )
+{
+#if defined(DEBUG) || defined(FORCE_NSPR_TRACE)
+ PRInt32 found, rc;
+ PRTraceEntry *foundEntries;
+ PRInt32 i;
+
+ foundEntries = (PRTraceEntry *)PR_Malloc( NUM_TRACE_RECORDS * sizeof(PRTraceEntry));
+ PR_ASSERT(foundEntries != NULL );
+
+ do
+ {
+ rc = PR_GetTraceEntries( foundEntries, NUM_TRACE_RECORDS, &found);
+ PR_LOG( lm, msgLevel,
+ ("SampleTrace: Lost Data: %ld found: %ld", rc, found ));
+
+ if ( found != 0)
+ {
+ for ( i = 0 ; i < found; i++ )
+ {
+ PR_LOG( lm, msgLevel,
+ ("SampleTrace, detail: Thread: %p, Time: %llX, UD0: %ld, UD1: %ld, UD2: %8.8ld",
+ (foundEntries +i)->thread,
+ (foundEntries +i)->time,
+ (foundEntries +i)->userData[0],
+ (foundEntries +i)->userData[1],
+ (foundEntries +i)->userData[2] ));
+ }
+ }
+ PR_Sleep(PR_MillisecondsToInterval(50));
+ }
+ while( found != 0 && activeThreads >= 1 );
+
+ PR_Free( foundEntries );
+
+ PR_EnterMonitor(mon);
+ --activeThreads;
+ PR_Notify( mon );
+ PR_ExitMonitor(mon);
+
+ PR_LOG( lm, msgLevel,
+ ("SampleTrace(): exiting"));
+
+#endif
+ return;
+} /* end RecordTrace() */
+
+/*
+** Basic trace test.
+*/
+static void TraceTest( void )
+{
+ PRInt32 i;
+ PRInt32 size;
+ PR_DEFINE_TRACE( th );
+ PRThread *t1, *t2;
+
+ PR_LOG( lm, msgLevel,
+ ("Begin TraceTest"));
+
+ size = SMALL_TRACE_BUFSIZE;
+ PR_SET_TRACE_OPTION( PRTraceBufSize, &size );
+ PR_GET_TRACE_OPTION( PRTraceBufSize, &i );
+
+ PR_CREATE_TRACE( th, "TraceTest", "tt2", "A description for the trace test" );
+ PR_CREATE_TRACE( th, "TraceTest", "tt3", "A description for the trace test" );
+ PR_CREATE_TRACE( th, "TraceTest", "tt4", "A description for the trace test" );
+ PR_CREATE_TRACE( th, "TraceTest", "tt5", "A description for the trace test" );
+ PR_CREATE_TRACE( th, "TraceTest", "tt6", "A description for the trace test" );
+ PR_CREATE_TRACE( th, "TraceTest", "tt7", "A description for the trace test" );
+ PR_CREATE_TRACE( th, "TraceTest", "tt8", "A description for the trace test" );
+
+ PR_CREATE_TRACE( th, "Trace Test", "tt0", "QName is Trace Test, not TraceTest" );
+ PR_CREATE_TRACE( th, "Trace Test", "tt1", "QName is Trace Test, not TraceTest" );
+ PR_CREATE_TRACE( th, "Trace Test", "tt2", "QName is Trace Test, not TraceTest" );
+ PR_CREATE_TRACE( th, "Trace Test", "tt3", "QName is Trace Test, not TraceTest" );
+ PR_CREATE_TRACE( th, "Trace Test", "tt4", "QName is Trace Test, not TraceTest" );
+ PR_CREATE_TRACE( th, "Trace Test", "tt5", "QName is Trace Test, not TraceTest" );
+ PR_CREATE_TRACE( th, "Trace Test", "tt6", "QName is Trace Test, not TraceTest" );
+ PR_CREATE_TRACE( th, "Trace Test", "tt7", "QName is Trace Test, not TraceTest" );
+ PR_CREATE_TRACE( th, "Trace Test", "tt8", "QName is Trace Test, not TraceTest" );
+ PR_CREATE_TRACE( th, "Trace Test", "tt9", "QName is Trace Test, not TraceTest" );
+ PR_CREATE_TRACE( th, "Trace Test", "tt10", "QName is Trace Test, not TraceTest" );
+
+
+
+ activeThreads += 2;
+ t1 = PR_CreateThread(PR_USER_THREAD,
+ RecordTrace, NULL,
+ PR_PRIORITY_NORMAL,
+ PR_GLOBAL_THREAD,
+ PR_UNJOINABLE_THREAD,
+ 0);
+ PR_ASSERT(t1);
+
+ t2 = PR_CreateThread(PR_USER_THREAD,
+ SampleTrace, 0,
+ PR_PRIORITY_NORMAL,
+ PR_GLOBAL_THREAD,
+ PR_UNJOINABLE_THREAD,
+ 0);
+ PR_ASSERT(t2);
+
+ ListTraces();
+
+ PR_GET_TRACE_HANDLE_FROM_NAME( th, "TraceTest","tt1" );
+ PR_ASSERT( th == hTrace );
+
+ PR_LOG( lm, msgLevel,
+ ("End TraceTest"));
+ return;
+} /* end TraceTest() */
+
+
+/*
+** Ordered lock test.
+*/
+static void OrderedLockTest( void )
+{
+ PR_LOG( lm, msgLevel,
+ ("Begin OrderedLockTest"));
+
+
+} /* end OrderedLockTest() */
+
+
+int main(int argc, char **argv)
+{
+#if defined(DEBUG) || defined(FORCE_NSPR_TRACE)
+ PRUint32 counter;
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "hdv:");
+ lm = PR_NewLogModule("Test");
+
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 'v': /* verbose mode */
+ msgLevel = (PRLogModuleLevel)atol( opt->value);
+ break;
+ case 'h': /* help message */
+ Help();
+ help = PR_TRUE;
+ break;
+ default:
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ PR_CREATE_TRACE( hTrace, "TraceTest", "tt1", "A description for the trace test" );
+ mon = PR_NewMonitor();
+ PR_EnterMonitor( mon );
+
+ TraceTest();
+ CounterTest();
+ OrderedLockTest();
+
+ /* Wait for all threads to exit */
+ while ( activeThreads > 0 ) {
+ if ( activeThreads == 1 ) {
+ PR_SET_TRACE_OPTION( PRTraceStopRecording, NULL );
+ }
+ PR_Wait(mon, PR_INTERVAL_NO_TIMEOUT);
+ PR_GET_COUNTER( counter, hCounter );
+ }
+ PR_ExitMonitor( mon );
+
+ /*
+ ** Evaluate results
+ */
+ PR_GET_COUNTER( counter, hCounter );
+ if ( counter != 0 )
+ {
+ failed = PR_TRUE;
+ PR_LOG( lm, msgLevel,
+ ("Expected counter == 0, found: %ld", counter));
+ printf("FAIL\n");
+ }
+ else
+ {
+ printf("PASS\n");
+ }
+
+
+ PR_DESTROY_COUNTER( hCounter );
+
+ PR_DestroyMonitor( mon );
+
+ PR_TRACE( hTrace, TraceFlow, 0xfff,0,0,0,0,0,0);
+ PR_DESTROY_TRACE( hTrace );
+#else
+ printf("Test not defined\n");
+#endif
+ return 0;
+} /* main() */
+/* end instrumt.c */
+
diff --git a/nsprpub/pr/tests/intrio.c b/nsprpub/pr/tests/intrio.c
new file mode 100644
index 0000000000..23d834d667
--- /dev/null
+++ b/nsprpub/pr/tests/intrio.c
@@ -0,0 +1,132 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * File: intrio.c
+ * Purpose: testing i/o interrupts (see Bugzilla bug #31120)
+ */
+
+#include "nspr.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* for synchronization between the main thread and iothread */
+static PRLock *lock;
+static PRCondVar *cvar;
+static PRBool iothread_ready;
+
+static void PR_CALLBACK AbortIO(void *arg)
+{
+ PRStatus rv;
+ PR_Sleep(PR_SecondsToInterval(2));
+ rv = PR_Interrupt((PRThread*)arg);
+ PR_ASSERT(PR_SUCCESS == rv);
+} /* AbortIO */
+
+static void PR_CALLBACK IOThread(void *arg)
+{
+ PRFileDesc *sock, *newsock;
+ PRNetAddr addr;
+
+ sock = PR_OpenTCPSocket(PR_AF_INET6);
+ if (sock == NULL) {
+ fprintf(stderr, "PR_OpenTCPSocket failed\n");
+ exit(1);
+ }
+ memset(&addr, 0, sizeof(addr));
+ if (PR_SetNetAddr(PR_IpAddrAny, PR_AF_INET6, 0, &addr) == PR_FAILURE) {
+ fprintf(stderr, "PR_SetNetAddr failed\n");
+ exit(1);
+ }
+ if (PR_Bind(sock, &addr) == PR_FAILURE) {
+ fprintf(stderr, "PR_Bind failed\n");
+ exit(1);
+ }
+ if (PR_Listen(sock, 5) == PR_FAILURE) {
+ fprintf(stderr, "PR_Listen failed\n");
+ exit(1);
+ }
+ /* tell the main thread that we are ready */
+ PR_Lock(lock);
+ iothread_ready = PR_TRUE;
+ PR_NotifyCondVar(cvar);
+ PR_Unlock(lock);
+ newsock = PR_Accept(sock, NULL, PR_INTERVAL_NO_TIMEOUT);
+ if (newsock != NULL) {
+ fprintf(stderr, "PR_Accept shouldn't have succeeded\n");
+ exit(1);
+ }
+ if (PR_GetError() != PR_PENDING_INTERRUPT_ERROR) {
+ fprintf(stderr, "PR_Accept failed (%d, %d)\n",
+ PR_GetError(), PR_GetOSError());
+ exit(1);
+ }
+ printf("PR_Accept() is interrupted as expected\n");
+ if (PR_Close(sock) == PR_FAILURE) {
+ fprintf(stderr, "PR_Close failed\n");
+ exit(1);
+ }
+}
+
+static void Test(PRThreadScope scope1, PRThreadScope scope2)
+{
+ PRThread *iothread, *abortio;
+
+ printf("A %s thread will be interrupted by a %s thread\n",
+ (scope1 == PR_LOCAL_THREAD ? "local" : "global"),
+ (scope2 == PR_LOCAL_THREAD ? "local" : "global"));
+ iothread_ready = PR_FALSE;
+ iothread = PR_CreateThread(
+ PR_USER_THREAD, IOThread, NULL, PR_PRIORITY_NORMAL,
+ scope1, PR_JOINABLE_THREAD, 0);
+ if (iothread == NULL) {
+ fprintf(stderr, "cannot create thread\n");
+ exit(1);
+ }
+ PR_Lock(lock);
+ while (!iothread_ready) {
+ PR_WaitCondVar(cvar, PR_INTERVAL_NO_TIMEOUT);
+ }
+ PR_Unlock(lock);
+ abortio = PR_CreateThread(
+ PR_USER_THREAD, AbortIO, iothread, PR_PRIORITY_NORMAL,
+ scope2, PR_JOINABLE_THREAD, 0);
+ if (abortio == NULL) {
+ fprintf(stderr, "cannot create thread\n");
+ exit(1);
+ }
+ if (PR_JoinThread(iothread) == PR_FAILURE) {
+ fprintf(stderr, "PR_JoinThread failed\n");
+ exit(1);
+ }
+ if (PR_JoinThread(abortio) == PR_FAILURE) {
+ fprintf(stderr, "PR_JoinThread failed\n");
+ exit(1);
+ }
+}
+
+int main(int argc, char **argv)
+{
+ PR_STDIO_INIT();
+ lock = PR_NewLock();
+ if (lock == NULL) {
+ fprintf(stderr, "PR_NewLock failed\n");
+ exit(1);
+ }
+ cvar = PR_NewCondVar(lock);
+ if (cvar == NULL) {
+ fprintf(stderr, "PR_NewCondVar failed\n");
+ exit(1);
+ }
+ /* test all four combinations */
+ Test(PR_LOCAL_THREAD, PR_LOCAL_THREAD);
+ Test(PR_LOCAL_THREAD, PR_GLOBAL_THREAD);
+ Test(PR_GLOBAL_THREAD, PR_LOCAL_THREAD);
+ Test(PR_GLOBAL_THREAD, PR_GLOBAL_THREAD);
+ printf("PASSED\n");
+ return 0;
+} /* main */
diff --git a/nsprpub/pr/tests/intrupt.c b/nsprpub/pr/tests/intrupt.c
new file mode 100644
index 0000000000..950d30d469
--- /dev/null
+++ b/nsprpub/pr/tests/intrupt.c
@@ -0,0 +1,379 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * File: intrupt.c
+ * Purpose: testing thread interrupts
+ */
+
+#include "plgetopt.h"
+#include "prcvar.h"
+#include "prerror.h"
+#include "prinit.h"
+#include "prinrval.h"
+#include "prio.h"
+#include "prlock.h"
+#include "prlog.h"
+#include "prthread.h"
+#include "prtypes.h"
+#include "prnetdb.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#define DEFAULT_TCP_PORT 12500
+
+static PRLock *ml = NULL;
+static PRCondVar *cv = NULL;
+
+static PRBool passed = PR_TRUE;
+static PRBool debug_mode = PR_FALSE;
+static PRThreadScope thread_scope = PR_LOCAL_THREAD;
+
+static void PR_CALLBACK AbortCV(void *arg)
+{
+ PRStatus rv;
+ PRThread *me = PR_GetCurrentThread();
+
+ /* some other thread (main) is doing the interrupt */
+ PR_Lock(ml);
+ rv = PR_WaitCondVar(cv, PR_INTERVAL_NO_TIMEOUT);
+ if (debug_mode) {
+ printf( "Expected interrupt on wait CV and ");
+ }
+ if (PR_FAILURE == rv)
+ {
+ if (PR_PENDING_INTERRUPT_ERROR == PR_GetError())
+ {
+ if (debug_mode) {
+ printf("got it\n");
+ }
+ }
+ else
+ {
+ if (debug_mode) {
+ printf("got random error\n");
+ }
+ passed = PR_FALSE;
+ }
+ }
+ else
+ {
+ if (debug_mode) {
+ printf("got a successful completion\n");
+ }
+ passed = PR_FALSE;
+ }
+
+ rv = PR_WaitCondVar(cv, 10);
+ if (debug_mode)
+ {
+ printf(
+ "Expected success on wait CV and %s\n",
+ (PR_SUCCESS == rv) ? "got it" : "failed");
+ }
+ passed = ((PR_TRUE == passed) && (PR_SUCCESS == rv)) ? PR_TRUE : PR_FALSE;
+
+ /* interrupt myself, then clear */
+ PR_Interrupt(me);
+ PR_ClearInterrupt();
+ rv = PR_WaitCondVar(cv, 10);
+ if (debug_mode)
+ {
+ printf("Expected success on wait CV and ");
+ if (PR_FAILURE == rv)
+ {
+ printf(
+ "%s\n", (PR_PENDING_INTERRUPT_ERROR == PR_GetError()) ?
+ "got interrupted" : "a random failure");
+ }
+ printf("got it\n");
+ }
+ passed = ((PR_TRUE == passed) && (PR_SUCCESS == rv)) ? PR_TRUE : PR_FALSE;
+
+ /* set, then wait - interrupt - then wait again */
+ PR_Interrupt(me);
+ rv = PR_WaitCondVar(cv, 10);
+ if (debug_mode) {
+ printf( "Expected interrupt on wait CV and ");
+ }
+ if (PR_FAILURE == rv)
+ {
+ if (PR_PENDING_INTERRUPT_ERROR == PR_GetError())
+ {
+ if (debug_mode) {
+ printf("got it\n");
+ }
+ }
+ else
+ {
+ if (debug_mode) {
+ printf("failed\n");
+ }
+ passed = PR_FALSE;
+ }
+ }
+ else
+ {
+ if (debug_mode) {
+ printf("got a successful completion\n");
+ }
+ passed = PR_FALSE;
+ }
+
+ rv = PR_WaitCondVar(cv, 10);
+ if (debug_mode)
+ {
+ printf(
+ "Expected success on wait CV and %s\n",
+ (PR_SUCCESS == rv) ? "got it" : "failed");
+ }
+ passed = ((PR_TRUE == passed) && (PR_SUCCESS == rv)) ? PR_TRUE : PR_FALSE;
+
+ PR_Unlock(ml);
+
+} /* AbortCV */
+
+static void PR_CALLBACK AbortIO(void *arg)
+{
+ PRStatus rv;
+ PR_Sleep(PR_SecondsToInterval(2));
+ rv = PR_Interrupt((PRThread*)arg);
+ PR_ASSERT(PR_SUCCESS == rv);
+} /* AbortIO */
+
+static void PR_CALLBACK AbortJoin(void *arg)
+{
+} /* AbortJoin */
+
+static void setup_listen_socket(PRFileDesc **listner, PRNetAddr *netaddr)
+{
+ PRStatus rv;
+ PRInt16 port = DEFAULT_TCP_PORT;
+
+ *listner = PR_NewTCPSocket();
+ PR_ASSERT(*listner != NULL);
+ memset(netaddr, 0, sizeof(*netaddr));
+ (*netaddr).inet.ip = PR_htonl(PR_INADDR_ANY);
+ (*netaddr).inet.family = PR_AF_INET;
+ do
+ {
+ (*netaddr).inet.port = PR_htons(port);
+ rv = PR_Bind(*listner, netaddr);
+ port += 1;
+ PR_ASSERT(port < (DEFAULT_TCP_PORT + 10));
+ } while (PR_FAILURE == rv);
+
+ rv = PR_Listen(*listner, 5);
+
+ if (PR_GetSockName(*listner, netaddr) < 0) {
+ if (debug_mode) {
+ printf("intrupt: ERROR - PR_GetSockName failed\n");
+ }
+ passed = PR_FALSE;
+ return;
+ }
+
+}
+
+static void PR_CALLBACK IntrBlock(void *arg)
+{
+ PRStatus rv;
+ PRNetAddr netaddr;
+ PRFileDesc *listner;
+
+ /* some other thread (main) is doing the interrupt */
+ /* block the interrupt */
+ PR_BlockInterrupt();
+ PR_Lock(ml);
+ rv = PR_WaitCondVar(cv, PR_SecondsToInterval(4));
+ PR_Unlock(ml);
+ if (debug_mode)
+ {
+ printf("Expected success on wait CV and ");
+ if (PR_FAILURE == rv)
+ {
+ printf(
+ "%s\n", (PR_PENDING_INTERRUPT_ERROR == PR_GetError()) ?
+ "got interrupted" : "got a random failure");
+ } else {
+ printf("got it\n");
+ }
+ }
+ passed = ((PR_TRUE == passed) && (PR_SUCCESS == rv)) ? PR_TRUE : PR_FALSE;
+
+ setup_listen_socket(&listner, &netaddr);
+ PR_UnblockInterrupt();
+ if (PR_Accept(listner, &netaddr, PR_INTERVAL_NO_TIMEOUT) == NULL)
+ {
+ PRInt32 error = PR_GetError();
+ if (debug_mode) {
+ printf("Expected interrupt on PR_Accept() and ");
+ }
+ if (PR_PENDING_INTERRUPT_ERROR == error)
+ {
+ if (debug_mode) {
+ printf("got it\n");
+ }
+ }
+ else
+ {
+ if (debug_mode) {
+ printf("failed\n");
+ }
+ passed = PR_FALSE;
+ }
+ }
+ else
+ {
+ if (debug_mode) {
+ printf("Failed to interrupt PR_Accept()\n");
+ }
+ passed = PR_FALSE;
+ }
+
+ (void)PR_Close(listner); listner = NULL;
+} /* TestIntrBlock */
+
+void PR_CALLBACK Intrupt(void *arg)
+{
+ PRStatus rv;
+ PRNetAddr netaddr;
+ PRFileDesc *listner;
+ PRThread *abortCV, *abortIO, *abortJoin, *intrBlock;
+
+ ml = PR_NewLock();
+ cv = PR_NewCondVar(ml);
+
+ /* Part I */
+ if (debug_mode) {
+ printf("Part I\n");
+ }
+ abortCV = PR_CreateThread(
+ PR_USER_THREAD, AbortCV, 0, PR_PRIORITY_NORMAL,
+ thread_scope, PR_JOINABLE_THREAD, 0);
+
+ PR_Sleep(PR_SecondsToInterval(2));
+ rv = PR_Interrupt(abortCV);
+ PR_ASSERT(PR_SUCCESS == rv);
+ rv = PR_JoinThread(abortCV);
+ PR_ASSERT(PR_SUCCESS == rv);
+
+ /* Part II */
+ if (debug_mode) {
+ printf("Part II\n");
+ }
+ abortJoin = PR_CreateThread(
+ PR_USER_THREAD, AbortJoin, 0, PR_PRIORITY_NORMAL,
+ thread_scope, PR_JOINABLE_THREAD, 0);
+ PR_Sleep(PR_SecondsToInterval(2));
+ if (debug_mode) {
+ printf("Expecting to interrupt an exited thread ");
+ }
+ rv = PR_Interrupt(abortJoin);
+ PR_ASSERT(PR_SUCCESS == rv);
+ rv = PR_JoinThread(abortJoin);
+ PR_ASSERT(PR_SUCCESS == rv);
+ if (debug_mode) {
+ printf("and succeeded\n");
+ }
+
+ /* Part III */
+ if (debug_mode) {
+ printf("Part III\n");
+ }
+ setup_listen_socket(&listner, &netaddr);
+ abortIO = PR_CreateThread(
+ PR_USER_THREAD, AbortIO, PR_GetCurrentThread(), PR_PRIORITY_NORMAL,
+ thread_scope, PR_JOINABLE_THREAD, 0);
+
+ if (PR_Accept(listner, &netaddr, PR_INTERVAL_NO_TIMEOUT) == NULL)
+ {
+ PRInt32 error = PR_GetError();
+ if (debug_mode) {
+ printf("Expected interrupt on PR_Accept() and ");
+ }
+ if (PR_PENDING_INTERRUPT_ERROR == error)
+ {
+ if (debug_mode) {
+ printf("got it\n");
+ }
+ }
+ else
+ {
+ if (debug_mode) {
+ printf("failed\n");
+ }
+ passed = PR_FALSE;
+ }
+ }
+ else
+ {
+ if (debug_mode) {
+ printf("Failed to interrupt PR_Accept()\n");
+ }
+ passed = PR_FALSE;
+ }
+
+ (void)PR_Close(listner); listner = NULL;
+
+ rv = PR_JoinThread(abortIO);
+ PR_ASSERT(PR_SUCCESS == rv);
+ /* Part VI */
+ if (debug_mode) {
+ printf("Part VI\n");
+ }
+ intrBlock = PR_CreateThread(
+ PR_USER_THREAD, IntrBlock, 0, PR_PRIORITY_NORMAL,
+ thread_scope, PR_JOINABLE_THREAD, 0);
+
+ PR_Sleep(PR_SecondsToInterval(2));
+ rv = PR_Interrupt(intrBlock);
+ PR_ASSERT(PR_SUCCESS == rv);
+ rv = PR_JoinThread(intrBlock);
+ PR_ASSERT(PR_SUCCESS == rv);
+
+ PR_DestroyCondVar(cv);
+ PR_DestroyLock(ml);
+} /* Intrupt */
+
+int main(int argc, char **argv)
+{
+ PRThread *intrupt;
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "dG");
+ 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 'G': /* use global threads */
+ thread_scope = PR_GLOBAL_THREAD;
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+ PR_STDIO_INIT();
+ intrupt = PR_CreateThread(
+ PR_USER_THREAD, Intrupt, NULL, PR_PRIORITY_NORMAL,
+ thread_scope, PR_JOINABLE_THREAD, 0);
+ if (intrupt == NULL) {
+ fprintf(stderr, "cannot create thread\n");
+ passed = PR_FALSE;
+ } else {
+ PRStatus rv;
+ rv = PR_JoinThread(intrupt);
+ PR_ASSERT(rv == PR_SUCCESS);
+ }
+ printf("%s\n", ((passed) ? "PASSED" : "FAILED"));
+ return ((passed) ? 0 : 1);
+} /* main */
+
+/* intrupt.c */
diff --git a/nsprpub/pr/tests/io_timeout.c b/nsprpub/pr/tests/io_timeout.c
new file mode 100644
index 0000000000..19d3daeccf
--- /dev/null
+++ b/nsprpub/pr/tests/io_timeout.c
@@ -0,0 +1,269 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+** Test socket IO timeouts
+**
+**
+**
+**
+** Modification History:
+** 14-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
+** The debug mode will print all of the printfs associated with this test.
+** The regress mode will be the default mode. Since the regress tool limits
+** the output to a one line status:PASS or FAIL,all of the printf statements
+** have been handled with an if (debug_mode) statement.
+***********************************************************************/
+/***********************************************************************
+** Includes
+***********************************************************************/
+/* Used to get the command line option */
+#include "plgetopt.h"
+
+#include <stdio.h>
+#include "nspr.h"
+
+#define NUM_THREADS 1
+#define BASE_PORT 8000
+#define DEFAULT_ACCEPT_TIMEOUT 2
+
+typedef struct threadInfo {
+ PRInt16 id;
+ PRInt16 accept_timeout;
+ PRLock *dead_lock;
+ PRCondVar *dead_cv;
+ PRInt32 *alive;
+} threadInfo;
+
+PRIntn failed_already = 0;
+PRIntn debug_mode = 0;
+
+#define LOCAL_SCOPE_STRING "LOCAL scope"
+#define GLOBAL_SCOPE_STRING "GLOBAL scope"
+#define GLOBAL_BOUND_SCOPE_STRING "GLOBAL_BOUND scope"
+
+void
+thread_main(void *_info)
+{
+ threadInfo *info = (threadInfo *)_info;
+ PRNetAddr listenAddr;
+ PRNetAddr clientAddr;
+ PRFileDesc *listenSock = NULL;
+ PRFileDesc *clientSock;
+ PRStatus rv;
+ PRThreadScope tscope;
+ char *scope_str;
+
+
+ if (debug_mode) {
+ printf("thread %d is alive\n", info->id);
+ }
+ tscope = PR_GetThreadScope(PR_GetCurrentThread());
+
+ switch(tscope) {
+ case PR_LOCAL_THREAD:
+ scope_str = LOCAL_SCOPE_STRING;
+ break;
+ case PR_GLOBAL_THREAD:
+ scope_str = GLOBAL_SCOPE_STRING;
+ break;
+ case PR_GLOBAL_BOUND_THREAD:
+ scope_str = GLOBAL_BOUND_SCOPE_STRING;
+ break;
+ default:
+ PR_NOT_REACHED("Invalid thread scope");
+ break;
+ }
+ printf("thread id %d, scope %s\n", info->id, scope_str);
+
+ listenSock = PR_NewTCPSocket();
+ if (!listenSock) {
+ if (debug_mode) {
+ printf("unable to create listen socket\n");
+ }
+ failed_already=1;
+ goto dead;
+ }
+
+ listenAddr.inet.family = PR_AF_INET;
+ listenAddr.inet.port = PR_htons(BASE_PORT + info->id);
+ listenAddr.inet.ip = PR_htonl(PR_INADDR_ANY);
+ rv = PR_Bind(listenSock, &listenAddr);
+ if (rv == PR_FAILURE) {
+ if (debug_mode) {
+ printf("unable to bind\n");
+ }
+ failed_already=1;
+ goto dead;
+ }
+
+ rv = PR_Listen(listenSock, 4);
+ if (rv == PR_FAILURE) {
+ if (debug_mode) {
+ printf("unable to listen\n");
+ }
+ failed_already=1;
+ goto dead;
+ }
+
+ if (debug_mode)
+ printf("thread %d going into accept for %d seconds\n",
+ info->id, info->accept_timeout + info->id);
+
+ clientSock = PR_Accept(listenSock, &clientAddr, PR_SecondsToInterval(info->accept_timeout +info->id));
+
+ if (clientSock == NULL) {
+ if (PR_GetError() == PR_IO_TIMEOUT_ERROR) {
+ if (debug_mode) {
+ printf("PR_Accept() timeout worked!\n");
+ printf("TEST PASSED! PR_Accept() returned error %d\n",
+ PR_IO_TIMEOUT_ERROR);
+ }
+ } else {
+ if (debug_mode)
+ printf("TEST FAILED! PR_Accept() returned error %d\n",
+ PR_GetError());
+ failed_already=1;
+ }
+ } else {
+ if (debug_mode) {
+ printf ("TEST FAILED! PR_Accept() succeeded?\n");
+ }
+ failed_already=1;
+ PR_Close(clientSock);
+ }
+
+dead:
+ if (listenSock) {
+ PR_Close(listenSock);
+ }
+ PR_Lock(info->dead_lock);
+ (*info->alive)--;
+ PR_NotifyCondVar(info->dead_cv);
+ PR_Unlock(info->dead_lock);
+
+ if (debug_mode) {
+ printf("thread %d is dead\n", info->id);
+ }
+
+ PR_Free(info);
+}
+
+void
+thread_test(PRThreadScope scope, PRInt32 num_threads)
+{
+ PRInt32 index;
+ PRThread *thr;
+ PRLock *dead_lock;
+ PRCondVar *dead_cv;
+ PRInt32 alive;
+
+ if (debug_mode) {
+ printf("IO Timeout test started with %d threads\n", num_threads);
+ }
+
+ dead_lock = PR_NewLock();
+ dead_cv = PR_NewCondVar(dead_lock);
+ alive = num_threads;
+
+ for (index = 0; index < num_threads; index++) {
+ threadInfo *info = (threadInfo *)PR_Malloc(sizeof(threadInfo));
+
+ info->id = index;
+ info->dead_lock = dead_lock;
+ info->dead_cv = dead_cv;
+ info->alive = &alive;
+ info->accept_timeout = DEFAULT_ACCEPT_TIMEOUT;
+
+ thr = PR_CreateThread( PR_USER_THREAD,
+ thread_main,
+ (void *)info,
+ PR_PRIORITY_NORMAL,
+ scope,
+ PR_UNJOINABLE_THREAD,
+ 0);
+
+ if (!thr) {
+ printf("Failed to create thread, error = %d(%d)\n",
+ PR_GetError(), PR_GetOSError());
+ failed_already=1;
+
+ PR_Lock(dead_lock);
+ alive--;
+ PR_Unlock(dead_lock);
+ }
+ }
+
+ PR_Lock(dead_lock);
+ while(alive) {
+ if (debug_mode) {
+ printf("main loop awake; alive = %d\n", alive);
+ }
+ 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)
+{
+ PRInt32 num_threads = 0;
+
+ /* The command line argument: -d is used to determine if the test is being run
+ in debug mode. The regress tool requires only one line output:PASS or FAIL.
+ All of the printfs associated with this test has been handled with a if (debug_mode)
+ test.
+ Usage: test_name [-d] [-t <threads>]
+ */
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "dt:");
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 'd': /* debug mode */
+ debug_mode = 1;
+ break;
+ case 't': /* threads to involve */
+ num_threads = atoi(opt->value);
+ break;
+ default:
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ /* main test */
+
+ if (0 == num_threads) {
+ num_threads = NUM_THREADS;
+ }
+
+ PR_Init(PR_USER_THREAD, PR_PRIORITY_LOW, 0);
+ PR_STDIO_INIT();
+
+ printf("test with global bound thread\n");
+ thread_test(PR_GLOBAL_BOUND_THREAD, num_threads);
+
+ printf("test with local thread\n");
+ thread_test(PR_LOCAL_THREAD, num_threads);
+
+ printf("test with global thread\n");
+ thread_test(PR_GLOBAL_THREAD, num_threads);
+
+ PR_Cleanup();
+
+ if (failed_already) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+}
diff --git a/nsprpub/pr/tests/io_timeoutk.c b/nsprpub/pr/tests/io_timeoutk.c
new file mode 100644
index 0000000000..a058655fdb
--- /dev/null
+++ b/nsprpub/pr/tests/io_timeoutk.c
@@ -0,0 +1,229 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+** name io_timeoutk.c
+** Description:Test socket IO timeouts (kernel level)
+**
+** Modification History:
+** 19-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
+** The debug mode will print all of the printfs associated with this test.
+** The regress mode will be the default mode. Since the regress tool limits
+** the output to a one line status:PASS or FAIL,all of the printf statements
+** have been handled with an if (debug_mode) statement.
+** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to
+** recognize the return code from tha main program.
+***********************************************************************/
+/***********************************************************************
+** Includes
+***********************************************************************/
+/* Used to get the command line option */
+#include "plgetopt.h"
+
+#include <stdio.h>
+#include "nspr.h"
+
+#define NUM_THREADS 1
+#define BASE_PORT 8000
+#define DEFAULT_ACCEPT_TIMEOUT 2
+
+typedef struct threadInfo {
+ PRInt16 id;
+ PRInt16 accept_timeout;
+ PRLock *dead_lock;
+ PRCondVar *dead_cv;
+ PRInt32 *alive;
+} threadInfo;
+
+PRIntn failed_already=0;
+PRIntn debug_mode;
+
+
+void
+thread_main(void *_info)
+{
+ threadInfo *info = (threadInfo *)_info;
+ PRNetAddr listenAddr;
+ PRNetAddr clientAddr;
+ PRFileDesc *listenSock = NULL;
+ PRFileDesc *clientSock;
+ PRStatus rv;
+
+ if (debug_mode) {
+ printf("thread %d is alive\n", info->id);
+ }
+
+ listenSock = PR_NewTCPSocket();
+ if (!listenSock) {
+ if (debug_mode) {
+ printf("unable to create listen socket\n");
+ }
+ goto dead;
+ }
+
+ listenAddr.inet.family = AF_INET;
+ listenAddr.inet.port = PR_htons(BASE_PORT + info->id);
+ listenAddr.inet.ip = PR_htonl(INADDR_ANY);
+ rv = PR_Bind(listenSock, &listenAddr);
+ if (rv == PR_FAILURE) {
+ if (debug_mode) {
+ printf("unable to bind\n");
+ }
+ goto dead;
+ }
+
+ rv = PR_Listen(listenSock, 4);
+ if (rv == PR_FAILURE) {
+ if (debug_mode) {
+ printf("unable to listen\n");
+ }
+ goto dead;
+ }
+
+ if (debug_mode) printf("thread %d going into accept for %d seconds\n",
+ info->id, info->accept_timeout + info->id);
+
+ clientSock = PR_Accept(listenSock, &clientAddr, PR_SecondsToInterval(info->accept_timeout +info->id));
+
+ if (clientSock == NULL) {
+ if (PR_GetError() == PR_IO_TIMEOUT_ERROR)
+ if (debug_mode) {
+ printf("PR_Accept() timeout worked!\n");
+ printf("TEST FAILED! PR_Accept() returned error %d\n",
+ PR_GetError());
+ }
+ else {
+ failed_already=1;
+ }
+ } else {
+ if (debug_mode) {
+ printf ("TEST FAILED! PR_Accept() succeeded?\n");
+ }
+ else {
+ failed_already=1;
+ }
+ PR_Close(clientSock);
+ }
+
+dead:
+ if (listenSock) {
+ PR_Close(listenSock);
+ }
+ PR_Lock(info->dead_lock);
+ (*info->alive)--;
+ PR_NotifyCondVar(info->dead_cv);
+ PR_Unlock(info->dead_lock);
+
+ if (debug_mode) {
+ printf("thread %d is dead\n", info->id);
+ }
+}
+
+void
+thread_test(PRInt32 scope, PRInt32 num_threads)
+{
+ PRInt32 index;
+ PRThread *thr;
+ PRLock *dead_lock;
+ PRCondVar *dead_cv;
+ PRInt32 alive;
+
+ if (debug_mode) {
+ printf("IO Timeout test started with %d threads\n", num_threads);
+ }
+
+ dead_lock = PR_NewLock();
+ dead_cv = PR_NewCondVar(dead_lock);
+ alive = num_threads;
+
+ for (index = 0; index < num_threads; index++) {
+ threadInfo *info = (threadInfo *)malloc(sizeof(threadInfo));
+
+ info->id = index;
+ info->dead_lock = dead_lock;
+ info->dead_cv = dead_cv;
+ info->alive = &alive;
+ info->accept_timeout = DEFAULT_ACCEPT_TIMEOUT;
+
+ thr = PR_CreateThread( PR_USER_THREAD,
+ thread_main,
+ (void *)info,
+ PR_PRIORITY_NORMAL,
+ scope,
+ PR_UNJOINABLE_THREAD,
+ 0);
+
+ if (!thr) {
+ PR_Lock(dead_lock);
+ alive--;
+ PR_Unlock(dead_lock);
+ }
+ }
+
+ PR_Lock(dead_lock);
+ while(alive) {
+ if (debug_mode) {
+ printf("main loop awake; alive = %d\n", alive);
+ }
+ PR_WaitCondVar(dead_cv, PR_INTERVAL_NO_TIMEOUT);
+ }
+ PR_Unlock(dead_lock);
+}
+
+int main(int argc, char **argv)
+{
+ PRInt32 num_threads;
+
+ /* The command line argument: -d is used to determine if the test is being run
+ in debug mode. The regress tool requires only one line output:PASS or FAIL.
+ All of the printfs associated with this test has been handled with a if (debug_mode)
+ test.
+ Usage: test_name -d
+ */
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "d:");
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 'd': /* debug mode */
+ debug_mode = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ /* main test */
+
+ if (argc > 2) {
+ num_threads = atoi(argv[2]);
+ }
+ else {
+ num_threads = NUM_THREADS;
+ }
+
+ PR_Init(PR_USER_THREAD, PR_PRIORITY_LOW, 0);
+ PR_STDIO_INIT();
+
+ if (debug_mode) {
+ printf("kernel level test\n");
+ }
+ thread_test(PR_GLOBAL_THREAD, num_threads);
+
+ PR_Cleanup();
+
+ if(failed_already) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+
+}
diff --git a/nsprpub/pr/tests/io_timeoutu.c b/nsprpub/pr/tests/io_timeoutu.c
new file mode 100644
index 0000000000..b6d9ccfa36
--- /dev/null
+++ b/nsprpub/pr/tests/io_timeoutu.c
@@ -0,0 +1,230 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+
+/*
+** name io_timeoutu.c
+** Description: Test socket IO timeouts (user level)
+**
+** Modification History:
+** 19-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
+** The debug mode will print all of the printfs associated with this test.
+** The regress mode will be the default mode. Since the regress tool limits
+** the output to a one line status:PASS or FAIL,all of the printf statements
+** have been handled with an if (debug_mode) statement.
+** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to
+** recognize the return code from tha main program.
+***********************************************************************/
+/***********************************************************************
+** Includes
+***********************************************************************/
+/* Used to get the command line option */
+#include "plgetopt.h"
+
+#include <stdio.h>
+#include "nspr.h"
+
+#define NUM_THREADS 1
+#define BASE_PORT 8000
+#define DEFAULT_ACCEPT_TIMEOUT 2
+
+typedef struct threadInfo {
+ PRInt16 id;
+ PRInt16 accept_timeout;
+ PRLock *dead_lock;
+ PRCondVar *dead_cv;
+ PRInt32 *alive;
+} threadInfo;
+PRIntn failed_already=0;
+PRIntn debug_mode;
+
+void
+thread_main(void *_info)
+{
+ threadInfo *info = (threadInfo *)_info;
+ PRNetAddr listenAddr;
+ PRNetAddr clientAddr;
+ PRFileDesc *listenSock = NULL;
+ PRFileDesc *clientSock;
+ PRStatus rv;
+
+ if (debug_mode) {
+ printf("thread %d is alive\n", info->id);
+ }
+
+ listenSock = PR_NewTCPSocket();
+ if (!listenSock) {
+ if (debug_mode) {
+ printf("unable to create listen socket\n");
+ }
+ goto dead;
+ }
+
+ listenAddr.inet.family = AF_INET;
+ listenAddr.inet.port = PR_htons(BASE_PORT + info->id);
+ listenAddr.inet.ip = PR_htonl(INADDR_ANY);
+ rv = PR_Bind(listenSock, &listenAddr);
+ if (rv == PR_FAILURE) {
+ if (debug_mode) {
+ printf("unable to bind\n");
+ }
+ goto dead;
+ }
+
+ rv = PR_Listen(listenSock, 4);
+ if (rv == PR_FAILURE) {
+ if (debug_mode) {
+ printf("unable to listen\n");
+ }
+ goto dead;
+ }
+
+ if (debug_mode) printf("thread %d going into accept for %d seconds\n",
+ info->id, info->accept_timeout + info->id);
+
+ clientSock = PR_Accept(
+ listenSock, &clientAddr, PR_SecondsToInterval(
+ info->accept_timeout + info->id));
+
+ if (clientSock == NULL) {
+ if (PR_GetError() == PR_IO_TIMEOUT_ERROR)
+ if (debug_mode) {
+ printf("PR_Accept() timeout worked!\n");
+ printf("TEST FAILED! PR_Accept() returned error %d\n",
+ }
+ PR_GetError());
+ else {
+ failed_already=1;
+ }
+ } else {
+ if (debug_mode) {
+ printf ("TEST FAILED! PR_Accept() succeeded?\n");
+ }
+ else {
+ failed_already=1;
+ }
+ PR_Close(clientSock);
+ }
+
+dead:
+ if (listenSock) {
+ PR_Close(listenSock);
+ }
+ PR_Lock(info->dead_lock);
+ (*info->alive)--;
+ PR_NotifyCondVar(info->dead_cv);
+ PR_Unlock(info->dead_lock);
+
+ if (debug_mode) {
+ printf("thread %d is dead\n", info->id);
+ }
+}
+
+void
+thread_test(PRInt32 scope, PRInt32 num_threads)
+{
+ PRInt32 index;
+ PRThread *thr;
+ PRLock *dead_lock;
+ PRCondVar *dead_cv;
+ PRInt32 alive;
+
+ if (debug_mode) {
+ printf("IO Timeout test started with %d threads\n", num_threads);
+ }
+
+ dead_lock = PR_NewLock();
+ dead_cv = PR_NewCondVar(dead_lock);
+ alive = num_threads;
+
+ for (index = 0; index < num_threads; index++) {
+ threadInfo *info = (threadInfo *)malloc(sizeof(threadInfo));
+
+ info->id = index;
+ info->dead_lock = dead_lock;
+ info->dead_cv = dead_cv;
+ info->alive = &alive;
+ info->accept_timeout = DEFAULT_ACCEPT_TIMEOUT;
+
+ thr = PR_CreateThread( PR_USER_THREAD,
+ thread_main,
+ (void *)info,
+ PR_PRIORITY_NORMAL,
+ scope,
+ PR_UNJOINABLE_THREAD,
+ 0);
+
+ if (!thr) {
+ PR_Lock(dead_lock);
+ alive--;
+ PR_Unlock(dead_lock);
+ }
+ }
+
+ PR_Lock(dead_lock);
+ while(alive) {
+ if (debug_mode) {
+ printf("main loop awake; alive = %d\n", alive);
+ }
+ PR_WaitCondVar(dead_cv, PR_INTERVAL_NO_TIMEOUT);
+ }
+ PR_Unlock(dead_lock);
+}
+
+int main(int argc, char **argv)
+{
+ PRInt32 num_threads;
+
+ /* The command line argument: -d is used to determine if the test is being run
+ in debug mode. The regress tool requires only one line output:PASS or FAIL.
+ All of the printfs associated with this test has been handled with a if (debug_mode)
+ test.
+ Usage: test_name -d
+ */
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "d:");
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 'd': /* debug mode */
+ debug_mode = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ /* main test */
+
+ if (argc > 2) {
+ num_threads = atoi(argv[2]);
+ }
+ else {
+ num_threads = NUM_THREADS;
+ }
+
+ PR_Init(PR_USER_THREAD, PR_PRIORITY_LOW, 0);
+ PR_STDIO_INIT();
+
+ if (debug_mode) {
+ printf("user level test\n");
+ }
+ thread_test(PR_LOCAL_THREAD, num_threads);
+
+ PR_Cleanup();
+ if(failed_already) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+
+
+}
diff --git a/nsprpub/pr/tests/ioconthr.c b/nsprpub/pr/tests/ioconthr.c
new file mode 100644
index 0000000000..3f5adcd572
--- /dev/null
+++ b/nsprpub/pr/tests/ioconthr.c
@@ -0,0 +1,114 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * This is a test for the io continuation thread machinery
+ * in pthreads.
+ */
+
+#include "nspr.h"
+#include <stdio.h>
+
+int num_threads = 10; /* must be an even number */
+PRThreadScope thread_scope = PR_GLOBAL_THREAD;
+
+void ThreadFunc(void *arg)
+{
+ PRFileDesc *fd = (PRFileDesc *) arg;
+ char buf[1024];
+ PRInt32 nbytes;
+ PRErrorCode err;
+
+ nbytes = PR_Recv(fd, buf, sizeof(buf), 0, PR_SecondsToInterval(20));
+ if (nbytes == -1) {
+ err = PR_GetError();
+ if (err != PR_PENDING_INTERRUPT_ERROR) {
+ fprintf(stderr, "PR_Recv failed: (%d, %d)\n",
+ err, PR_GetOSError());
+ PR_ProcessExit(1);
+ }
+ /*
+ * 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);
+ }
+ } else {
+ fprintf(stderr, "PR_Recv received %d bytes!?\n", nbytes);
+ PR_ProcessExit(1);
+ }
+}
+
+int main(int argc, char **argv)
+{
+ PRFileDesc **fds;
+ PRThread **threads;
+ PRIntervalTime start, elapsed;
+ int index;
+
+ fds = (PRFileDesc **) PR_MALLOC(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; index++) {
+ if (PR_NewTCPSocketPair(&fds[2 * index]) == PR_FAILURE) {
+ fprintf(stderr, "PR_NewTCPSocket failed\n");
+ PR_ProcessExit(1);
+ }
+ threads[index] = PR_CreateThread(
+ PR_USER_THREAD, ThreadFunc, fds[2 * index],
+ PR_PRIORITY_NORMAL, thread_scope, PR_JOINABLE_THREAD, 0);
+ if (NULL == threads[index]) {
+ fprintf(stderr, "PR_CreateThread failed\n");
+ PR_ProcessExit(1);
+ }
+ }
+
+ /* Let the threads block in PR_Recv */
+ PR_Sleep(PR_SecondsToInterval(2));
+
+ printf("Interrupting the threads\n");
+ fflush(stdout);
+ start = PR_IntervalNow();
+ for (index = 0; index < num_threads; index++) {
+ if (PR_Interrupt(threads[index]) == PR_FAILURE) {
+ fprintf(stderr, "PR_Interrupt failed\n");
+ PR_ProcessExit(1);
+ }
+ }
+ for (index = 0; index < num_threads; index++) {
+ if (PR_JoinThread(threads[index]) == PR_FAILURE) {
+ fprintf(stderr, "PR_JoinThread failed\n");
+ PR_ProcessExit(1);
+ }
+ }
+ elapsed = (PRIntervalTime)(PR_IntervalNow() - start);
+ printf("Threads terminated in %d milliseconds\n",
+ PR_IntervalToMilliseconds(elapsed));
+ fflush(stdout);
+
+ /* We are being very generous and allow 10 seconds. */
+ if (elapsed >= PR_SecondsToInterval(10)) {
+ fprintf(stderr, "Interrupting threads took longer than 10 seconds!!\n");
+ PR_ProcessExit(1);
+ }
+
+ 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");
+ PR_Cleanup();
+ return 0;
+}
diff --git a/nsprpub/pr/tests/ipv6.c b/nsprpub/pr/tests/ipv6.c
new file mode 100644
index 0000000000..cc323e1e6c
--- /dev/null
+++ b/nsprpub/pr/tests/ipv6.c
@@ -0,0 +1,228 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "prio.h"
+#include "prenv.h"
+#include "prmem.h"
+#include "prlink.h"
+#include "prsystem.h"
+#include "prnetdb.h"
+#include "prprf.h"
+#include "prvrsion.h"
+
+#include "plerror.h"
+#include "plgetopt.h"
+#include "obsolete/probslet.h"
+
+#include <string.h>
+
+#define DNS_BUFFER 100
+#define ADDR_BUFFER 100
+#define HOST_BUFFER 1024
+#define PROTO_BUFFER 1500
+
+#define NETADDR_SIZE(addr) \
+ (PR_AF_INET == (addr)->raw.family ? \
+ sizeof((addr)->inet) : sizeof((addr)->ipv6))
+
+static PRFileDesc *err = NULL;
+
+static void Help(void)
+{
+ PR_fprintf(err, "Usage: [-V] [-h]\n");
+ PR_fprintf(err, "\t<nul> Name of host to lookup (default: self)\n");
+ PR_fprintf(err, "\t-V Display runtime version info (default: FALSE)\n");
+ PR_fprintf(err, "\t-h This message and nothing else\n");
+} /* Help */
+
+static void DumpAddr(const PRNetAddr* address, const char *msg)
+{
+ PRUint32 *word = (PRUint32*)address;
+ PRUint32 addr_len = sizeof(PRNetAddr);
+ PR_fprintf(err, "%s[%d]\t", msg, NETADDR_SIZE(address));
+ while (addr_len > 0)
+ {
+ PR_fprintf(err, " %08x", *word++);
+ addr_len -= sizeof(PRUint32);
+ }
+ PR_fprintf(err, "\n");
+} /* DumpAddr */
+
+static PRStatus PrintAddress(const PRNetAddr* address)
+{
+ PRNetAddr translation;
+ char buffer[ADDR_BUFFER];
+ PRStatus rv = PR_NetAddrToString(address, buffer, sizeof(buffer));
+ if (PR_FAILURE == rv) {
+ PL_FPrintError(err, "PR_NetAddrToString");
+ }
+ else
+ {
+ PR_fprintf(err, "\t%s\n", buffer);
+ memset(&translation, 0, sizeof(translation));
+ rv = PR_StringToNetAddr(buffer, &translation);
+ if (PR_FAILURE == rv) {
+ PL_FPrintError(err, "PR_StringToNetAddr");
+ }
+ else
+ {
+ PRSize addr_len = NETADDR_SIZE(address);
+ if (0 != memcmp(address, &translation, addr_len))
+ {
+ PR_fprintf(err, "Address translations do not match\n");
+ DumpAddr(address, "original");
+ DumpAddr(&translation, "translate");
+ rv = PR_FAILURE;
+ }
+ }
+ }
+ return rv;
+} /* PrintAddress */
+
+int main(int argc, char **argv)
+{
+ PRStatus rv;
+ PLOptStatus os;
+ PRHostEnt host;
+ PRProtoEnt proto;
+ const char *name = NULL;
+ PRBool failed = PR_FALSE, version = PR_FALSE;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "Vh");
+
+ err = PR_GetSpecialFD(PR_StandardError);
+
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 0: /* Name of host to lookup */
+ name = opt->value;
+ break;
+ case 'V': /* Do version discovery */
+ version = PR_TRUE;
+ break;
+ case 'h': /* user wants some guidance */
+ default:
+ Help(); /* so give him an earful */
+ return 2; /* but not a lot else */
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ if (version)
+ {
+#if defined(WINNT)
+#define NSPR_LIB "libnspr4"
+#else
+#define NSPR_LIB "nspr4"
+#endif
+ const PRVersionDescription *version_info;
+ char *nspr_path = PR_GetEnv("LD_LIBRARY_PATH");
+ char *nspr_name = PR_GetLibraryName(nspr_path, NSPR_LIB);
+ PRLibrary *runtime = PR_LoadLibrary(nspr_name);
+ if (NULL == runtime) {
+ PL_FPrintError(err, "PR_LoadLibrary");
+ }
+ else
+ {
+ versionEntryPointType versionPoint = (versionEntryPointType)
+ PR_FindSymbol(runtime, "libVersionPoint");
+ if (NULL == versionPoint) {
+ PL_FPrintError(err, "PR_FindSymbol");
+ }
+ else
+ {
+ char buffer[100];
+ PRExplodedTime exploded;
+ version_info = versionPoint();
+ (void)PR_fprintf(err, "Runtime library version information\n");
+ PR_ExplodeTime(
+ version_info->buildTime, PR_GMTParameters, &exploded);
+ (void)PR_FormatTime(
+ buffer, sizeof(buffer), "%d %b %Y %H:%M:%S", &exploded);
+ (void)PR_fprintf(err, " Build time: %s GMT\n", buffer);
+ (void)PR_fprintf(
+ err, " Build time: %s\n", version_info->buildTimeString);
+ (void)PR_fprintf(
+ err, " %s V%u.%u.%u (%s%s%s)\n",
+ version_info->description,
+ version_info->vMajor,
+ version_info->vMinor,
+ version_info->vPatch,
+ (version_info->beta ? " beta " : ""),
+ (version_info->debug ? " debug " : ""),
+ (version_info->special ? " special" : ""));
+ (void)PR_fprintf(err, " filename: %s\n", version_info->filename);
+ (void)PR_fprintf(err, " security: %s\n", version_info->security);
+ (void)PR_fprintf(err, " copyright: %s\n", version_info->copyright);
+ (void)PR_fprintf(err, " comment: %s\n", version_info->comment);
+ }
+ }
+ if (NULL != nspr_name) {
+ PR_FreeLibraryName(nspr_name);
+ }
+ }
+
+ {
+ if (NULL == name)
+ {
+ char *me = (char*)PR_MALLOC(DNS_BUFFER);
+ rv = PR_GetSystemInfo(PR_SI_HOSTNAME, me, DNS_BUFFER);
+ if (PR_FAILURE == rv)
+ {
+ failed = PR_TRUE;
+ PL_FPrintError(err, "PR_GetSystemInfo");
+ return 2;
+ }
+ name = me; /* just leak the storage */
+ }
+ }
+
+ {
+ char buffer[HOST_BUFFER];
+ PR_fprintf(err, "Translating the name %s ...", name);
+
+ rv = PR_GetHostByName(name, buffer, sizeof(buffer), &host);
+ if (PR_FAILURE == rv)
+ {
+ failed = PR_TRUE;
+ PL_FPrintError(err, "PR_GetHostByName");
+ }
+ else
+ {
+ PRIntn index = 0;
+ PRNetAddr address;
+ memset(&address, 0, sizeof(PRNetAddr));
+ PR_fprintf(err, "success .. enumerating results\n");
+ do
+ {
+ index = PR_EnumerateHostEnt(index, &host, 0, &address);
+ if (index > 0) {
+ PrintAddress(&address);
+ }
+ else if (-1 == index)
+ {
+ failed = PR_TRUE;
+ PL_FPrintError(err, "PR_EnumerateHostEnt");
+ }
+ } while (index > 0);
+ }
+ }
+
+
+ {
+ char buffer[PROTO_BUFFER];
+ /*
+ ** Get Proto by name/number
+ */
+ rv = PR_GetProtoByName("tcp", &buffer[1], sizeof(buffer) - 1, &proto);
+ rv = PR_GetProtoByNumber(6, &buffer[3], sizeof(buffer) - 3, &proto);
+ }
+
+ return (failed) ? 1 : 0;
+}
diff --git a/nsprpub/pr/tests/join.c b/nsprpub/pr/tests/join.c
new file mode 100644
index 0000000000..24238e6e05
--- /dev/null
+++ b/nsprpub/pr/tests/join.c
@@ -0,0 +1,264 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/***********************************************************************
+**
+** Name: dbmalloc1.c
+**
+** Description: Tests PR_SetMallocCountdown PR_ClearMallocCountdown functions.
+**
+** Modification History:
+**
+** 19-May-97 AGarcia - separate the four join tests into different unit test modules.
+** AGarcia- Converted the test to accomodate the debug_mode flag.
+** The debug mode will print all of the printfs associated with this test.
+** The regress mode will be the default mode. Since the regress tool limits
+** the output to a one line status:PASS or FAIL,all of the printf statements
+** have been handled with an if (debug_mode) statement.
+***********************************************************************/
+
+/***********************************************************************
+** Includes
+***********************************************************************/
+/* Used to get the command line option */
+#include "plgetopt.h"
+#include "prttools.h"
+
+#include "nspr.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/***********************************************************************
+** PRIVATE FUNCTION: Test_Result
+** DESCRIPTION: Used in conjunction with the regress tool, prints out the
+** status of the test case.
+** INPUTS: PASS/FAIL
+** OUTPUTS: None
+** RETURN: None
+** SIDE EFFECTS:
+**
+** RESTRICTIONS:
+** None
+** MEMORY: NA
+** ALGORITHM: Determine what the status is and print accordingly.
+**
+***********************************************************************/
+
+
+static void Test_Result (int result)
+{
+ if (result == PASS) {
+ printf ("PASS\n");
+ }
+ else {
+ printf ("FAIL\n");
+ }
+ exit (1);
+}
+
+
+/*
+ Program to test joining of threads. Two threads are created. One
+ to be waited upon until it has started. The other to join after it has
+ completed.
+*/
+
+
+static void PR_CALLBACK lowPriority(void *arg)
+{
+}
+
+static void PR_CALLBACK highPriority(void *arg)
+{
+}
+
+static void PR_CALLBACK unjoinable(void *arg)
+{
+ PR_Sleep(PR_INTERVAL_NO_TIMEOUT);
+}
+
+void runTest(PRThreadScope scope1, PRThreadScope scope2)
+{
+ PRThread *low,*high;
+
+ /* create the low and high priority threads */
+
+ low = PR_CreateThread(PR_USER_THREAD,
+ lowPriority, 0,
+ PR_PRIORITY_LOW,
+ scope1,
+ PR_JOINABLE_THREAD,
+ 0);
+ if (!low) {
+ if (debug_mode) {
+ printf("\tcannot create low priority thread\n");
+ }
+ else {
+ Test_Result(FAIL);
+ }
+ return;
+ }
+
+ high = PR_CreateThread(PR_USER_THREAD,
+ highPriority, 0,
+ PR_PRIORITY_HIGH,
+ scope2,
+ PR_JOINABLE_THREAD,
+ 0);
+ if (!high) {
+ if (debug_mode) {
+ printf("\tcannot create high priority thread\n");
+ }
+ else {
+ Test_Result(FAIL);
+ }
+ return;
+ }
+
+ /* Do the joining for both threads */
+ if (PR_JoinThread(low) == PR_FAILURE) {
+ if (debug_mode) {
+ printf("\tcannot join low priority thread\n");
+ }
+ else {
+ Test_Result (FAIL);
+ }
+ return;
+ } else {
+ if (debug_mode) {
+ printf("\tjoined low priority thread\n");
+ }
+ }
+ if (PR_JoinThread(high) == PR_FAILURE) {
+ if (debug_mode) {
+ printf("\tcannot join high priority thread\n");
+ }
+ else {
+ Test_Result(FAIL);
+ }
+ return;
+ } else {
+ if (debug_mode) {
+ printf("\tjoined high priority thread\n");
+ }
+ }
+}
+
+void joinWithUnjoinable(void)
+{
+ PRThread *thread;
+
+ /* create the unjoinable thread */
+
+ thread = PR_CreateThread(PR_USER_THREAD,
+ unjoinable, 0,
+ PR_PRIORITY_NORMAL,
+ PR_GLOBAL_THREAD,
+ PR_UNJOINABLE_THREAD,
+ 0);
+ if (!thread) {
+ if (debug_mode) {
+ printf("\tcannot create unjoinable thread\n");
+ }
+ else {
+ Test_Result(FAIL);
+ }
+ return;
+ }
+
+ if (PR_JoinThread(thread) == PR_SUCCESS) {
+ if (debug_mode) {
+ printf("\tsuccessfully joined with unjoinable thread?!\n");
+ }
+ else {
+ Test_Result(FAIL);
+ }
+ return;
+ } else {
+ if (debug_mode) {
+ printf("\tcannot join with unjoinable thread, as expected\n");
+ }
+ if (PR_GetError() != PR_INVALID_ARGUMENT_ERROR) {
+ if (debug_mode) {
+ printf("\tWrong error code\n");
+ }
+ else {
+ Test_Result(FAIL);
+ }
+ return;
+ }
+ }
+ if (PR_Interrupt(thread) == PR_FAILURE) {
+ if (debug_mode) {
+ printf("\tcannot interrupt unjoinable thread\n");
+ }
+ else {
+ Test_Result(FAIL);
+ }
+ return;
+ } else {
+ if (debug_mode) {
+ printf("\tinterrupted unjoinable thread\n");
+ }
+ }
+}
+
+static PRIntn PR_CALLBACK RealMain(int argc, char **argv)
+{
+ /* The command line argument: -d is used to determine if the test is being run
+ in debug mode. The regress tool requires only one line output:PASS or FAIL.
+ All of the printfs associated with this test has been handled with a if (debug_mode)
+ test.
+ Usage: test_name -d
+ */
+
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "d:");
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 'd': /* debug mode */
+ debug_mode = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ /* main test */
+ printf("User-User test\n");
+ runTest(PR_LOCAL_THREAD, PR_LOCAL_THREAD);
+ printf("User-Kernel test\n");
+ runTest(PR_LOCAL_THREAD, PR_GLOBAL_THREAD);
+ printf("Kernel-User test\n");
+ runTest(PR_GLOBAL_THREAD, PR_LOCAL_THREAD);
+ printf("Kernel-Kernel test\n");
+ runTest(PR_GLOBAL_THREAD, PR_GLOBAL_THREAD);
+ printf("Join with unjoinable thread\n");
+ joinWithUnjoinable();
+
+ printf("PASSED\n");
+
+ return 0;
+}
+
+
+
+
+int main(int argc, char **argv)
+{
+ PRIntn rv;
+
+ PR_STDIO_INIT();
+ rv = PR_Initialize(RealMain, argc, argv, 0);
+ return rv;
+} /* main */
diff --git a/nsprpub/pr/tests/joinkk.c b/nsprpub/pr/tests/joinkk.c
new file mode 100644
index 0000000000..4e7b2b5e14
--- /dev/null
+++ b/nsprpub/pr/tests/joinkk.c
@@ -0,0 +1,174 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/***********************************************************************
+**
+** Name: dbmalloc1.c
+**
+** Description: Tests PR_SetMallocCountdown PR_ClearMallocCountdown functions.
+**
+** Modification History:
+**
+** 19-May-97 AGarcia - separate the four join tests into different unit test modules.
+** AGarcia- Converted the test to accomodate the debug_mode flag.
+** The debug mode will print all of the printfs associated with this test.
+** The regress mode will be the default mode. Since the regress tool limits
+** the output to a one line status:PASS or FAIL,all of the printf statements
+** have been handled with an if (debug_mode) statement.
+** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to
+** recognize the return code from tha main program.
+***********************************************************************/
+
+/***********************************************************************
+** Includes
+***********************************************************************/
+/* Used to get the command line option */
+#include "plgetopt.h"
+
+#include "nspr.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+PRIntn failed_already=0;
+PRIntn debug_mode;
+/*
+ Program to test joining of threads. Two threads are created. One
+ to be waited upon until it has started. The other to join after it has
+ completed.
+*/
+
+
+static void lowPriority(void *arg)
+{
+}
+
+static void highPriority(void *arg)
+{
+}
+
+void runTest(PRThreadScope scope1, PRThreadScope scope2)
+{
+ PRThread *low,*high;
+
+ /* create the low and high priority threads */
+
+ low = PR_CreateThread(PR_USER_THREAD,
+ lowPriority, 0,
+ PR_PRIORITY_LOW,
+ scope1,
+ PR_JOINABLE_THREAD,
+ 0);
+ if (!low) {
+ if (debug_mode) {
+ printf("\tcannot create low priority thread\n");
+ }
+ else {
+ failed_already=1;
+ }
+ return;
+ }
+
+ high = PR_CreateThread(PR_USER_THREAD,
+ highPriority, 0,
+ PR_PRIORITY_HIGH,
+ scope2,
+ PR_JOINABLE_THREAD,
+ 0);
+ if (!high) {
+ if (debug_mode) {
+ printf("\tcannot create high priority thread\n");
+ }
+ else {
+ failed_already=1;
+ }
+ return;
+ }
+
+ /* Do the joining for both threads */
+ if (PR_JoinThread(low) == PR_FAILURE) {
+ if (debug_mode) {
+ printf("\tcannot join low priority thread\n");
+ }
+ else {
+ failed_already=1;
+ }
+ return;
+ } else {
+ if (debug_mode) {
+ printf("\tjoined low priority thread\n");
+ }
+ }
+ if (PR_JoinThread(high) == PR_FAILURE) {
+ if (debug_mode) {
+ printf("\tcannot join high priority thread\n");
+ }
+ else {
+ failed_already=1;
+ }
+ return;
+ } else {
+ if (debug_mode) {
+ printf("\tjoined high priority thread\n");
+ }
+ }
+}
+
+static PRIntn PR_CALLBACK RealMain( PRIntn argc, char **argv )
+{
+ /* The command line argument: -d is used to determine if the test is being run
+ in debug mode. The regress tool requires only one line output:PASS or FAIL.
+ All of the printfs associated with this test has been handled with a if (debug_mode)
+ test.
+ Usage: test_name -d
+ */
+
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "d:");
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 'd': /* debug mode */
+ debug_mode = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ /* main test */
+
+ if (debug_mode) {
+ printf("Kernel-Kernel test\n");
+ }
+ runTest(PR_GLOBAL_THREAD, PR_GLOBAL_THREAD);
+
+ if(failed_already)
+ {
+ printf("FAIL\n");
+ return 1;
+ }
+ else
+ {
+ printf("PASS\n");
+ return 0;
+ }
+
+}
+
+int main(int argc, char **argv)
+{
+ PRIntn rv;
+
+ PR_STDIO_INIT();
+ rv = PR_Initialize(RealMain, argc, argv, 0);
+ return rv;
+} /* main */
diff --git a/nsprpub/pr/tests/joinku.c b/nsprpub/pr/tests/joinku.c
new file mode 100644
index 0000000000..cd83b6cb42
--- /dev/null
+++ b/nsprpub/pr/tests/joinku.c
@@ -0,0 +1,181 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/***********************************************************************
+**
+** Name: dbmalloc1.c
+**
+** Description: Tests PR_SetMallocCountdown PR_ClearMallocCountdown functions.
+**
+** Modification History:
+**
+** 19-May-97 AGarcia - separate the four join tests into different unit test modules.
+** AGarcia- Converted the test to accomodate the debug_mode flag.
+** The debug mode will print all of the printfs associated with this test.
+** The regress mode will be the default mode. Since the regress tool limits
+** the output to a one line status:PASS or FAIL,all of the printf statements
+** have been handled with an if (debug_mode) statement.
+** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to
+** recognize the return code from tha main program.
+***********************************************************************/
+
+/***********************************************************************
+** Includes
+***********************************************************************/
+/* Used to get the command line option */
+#include "plgetopt.h"
+
+#include "nspr.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+PRIntn failed_already=0;
+PRIntn debug_mode;
+
+
+/*
+ Program to test joining of threads. Two threads are created. One
+ to be waited upon until it has started. The other to join after it has
+ completed.
+*/
+
+
+static void lowPriority(void *arg)
+{
+}
+
+static void highPriority(void *arg)
+{
+}
+
+void runTest(PRThreadScope scope1, PRThreadScope scope2)
+{
+ PRThread *low,*high;
+
+ /* create the low and high priority threads */
+
+ low = PR_CreateThread(PR_USER_THREAD,
+ lowPriority, 0,
+ PR_PRIORITY_LOW,
+ scope1,
+ PR_JOINABLE_THREAD,
+ 0);
+ if (!low) {
+ if (debug_mode) {
+ printf("\tcannot create low priority thread\n");
+ }
+ else {
+ failed_already=1;
+ }
+ return;
+ }
+
+ high = PR_CreateThread(PR_USER_THREAD,
+ highPriority, 0,
+ PR_PRIORITY_HIGH,
+ scope2,
+ PR_JOINABLE_THREAD,
+ 0);
+ if (!high) {
+ if (debug_mode) {
+ printf("\tcannot create high priority thread\n");
+ }
+ else {
+ failed_already=1;
+ }
+ return;
+ }
+
+ /* Do the joining for both threads */
+ if (PR_JoinThread(low) == PR_FAILURE) {
+ if (debug_mode) {
+ printf("\tcannot join low priority thread\n");
+ }
+ else {
+ failed_already=1;
+ }
+ return;
+ } else {
+ if (debug_mode) {
+ printf("\tjoined low priority thread\n");
+ }
+ }
+ if (PR_JoinThread(high) == PR_FAILURE) {
+ if (debug_mode) {
+ printf("\tcannot join high priority thread\n");
+ }
+ else {
+ failed_already=1;
+ }
+ return;
+ } else {
+ if (debug_mode) {
+ printf("\tjoined high priority thread\n");
+ }
+ }
+}
+
+static PRIntn PR_CALLBACK RealMain( PRIntn argc, char **argv )
+{
+ /* The command line argument: -d is used to determine if the test is being run
+ in debug mode. The regress tool requires only one line output:PASS or FAIL.
+ All of the printfs associated with this test has been handled with a if (debug_mode)
+ test.
+ Usage: test_name -d
+ */
+
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "d:");
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 'd': /* debug mode */
+ debug_mode = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
+ PR_STDIO_INIT();
+
+ /* main test */
+
+ if (debug_mode) {
+ printf("Kernel-User test\n");
+ }
+ runTest(PR_GLOBAL_THREAD, PR_LOCAL_THREAD);
+
+
+ if(failed_already)
+ {
+ printf("FAIL\n");
+ return 1;
+ }
+ else
+ {
+ printf("PASS\n");
+ return 0;
+ }
+
+}
+
+
+int main(int argc, char **argv)
+{
+ PRIntn rv;
+
+ PR_STDIO_INIT();
+ rv = PR_Initialize(RealMain, argc, argv, 0);
+ return rv;
+} /* main */
diff --git a/nsprpub/pr/tests/joinuk.c b/nsprpub/pr/tests/joinuk.c
new file mode 100644
index 0000000000..418c5e0e91
--- /dev/null
+++ b/nsprpub/pr/tests/joinuk.c
@@ -0,0 +1,177 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/***********************************************************************
+**
+** Name: joinuk.c
+**
+** Description: Join kernel - user
+**
+** Modification History:
+**
+** 19-May-97 AGarcia - separate the four join tests into different unit test modules.
+** AGarcia- Converted the test to accomodate the debug_mode flag.
+** The debug mode will print all of the printfs associated with this test.
+** The regress mode will be the default mode. Since the regress tool limits
+** the output to a one line status:PASS or FAIL,all of the printf statements
+** have been handled with an if (debug_mode) statement.
+** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to
+** recognize the return code from tha main program.
+***********************************************************************/
+
+/***********************************************************************
+** Includes
+***********************************************************************/
+/* Used to get the command line option */
+#include "plgetopt.h"
+
+#include "nspr.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+PRIntn failed_already=0;
+PRIntn debug_mode;
+/*
+ Program to test joining of threads. Two threads are created. One
+ to be waited upon until it has started. The other to join after it has
+ completed.
+*/
+
+
+static void lowPriority(void *arg)
+{
+}
+
+static void highPriority(void *arg)
+{
+}
+
+void runTest(PRThreadScope scope1, PRThreadScope scope2)
+{
+ PRThread *low,*high;
+
+ /* create the low and high priority threads */
+
+ low = PR_CreateThread(PR_USER_THREAD,
+ lowPriority, 0,
+ PR_PRIORITY_LOW,
+ scope1,
+ PR_JOINABLE_THREAD,
+ 0);
+ if (!low) {
+ if (debug_mode) {
+ printf("\tcannot create low priority thread\n");
+ }
+ else {
+ failed_already=1;
+ }
+ return;
+ }
+
+ high = PR_CreateThread(PR_USER_THREAD,
+ highPriority, 0,
+ PR_PRIORITY_HIGH,
+ scope2,
+ PR_JOINABLE_THREAD,
+ 0);
+ if (!high) {
+ if (debug_mode) {
+ printf("\tcannot create high priority thread\n");
+ }
+ else {
+ failed_already=1;
+ }
+ return;
+ }
+
+ /* Do the joining for both threads */
+ if (PR_JoinThread(low) == PR_FAILURE) {
+ if (debug_mode) {
+ printf("\tcannot join low priority thread\n");
+ }
+ else {
+ failed_already=1;
+ }
+ return;
+ } else {
+ if (debug_mode) {
+ printf("\tjoined low priority thread\n");
+ }
+ }
+ if (PR_JoinThread(high) == PR_FAILURE) {
+ if (debug_mode) {
+ printf("\tcannot join high priority thread\n");
+ }
+ else {
+ failed_already=1;
+ }
+ return;
+ } else {
+ if (debug_mode) {
+ printf("\tjoined high priority thread\n");
+ }
+ }
+}
+
+static PRIntn PR_CALLBACK RealMain( PRIntn argc, char **argv )
+{
+ /* The command line argument: -d is used to determine if the test is being run
+ in debug mode. The regress tool requires only one line output:PASS or FAIL.
+ All of the printfs associated with this test has been handled with a if (debug_mode)
+ test.
+ Usage: test_name -d
+ */
+
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "d:");
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 'd': /* debug mode */
+ debug_mode = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
+ PR_STDIO_INIT();
+
+ /* main test */
+
+ if (debug_mode) {
+ printf("User-Kernel test\n");
+ }
+ runTest(PR_LOCAL_THREAD, PR_GLOBAL_THREAD);
+
+
+ if(failed_already)
+ {
+ printf("FAIL\n");
+ return 1;
+ } else
+ {
+ printf("PASS\n");
+ return 0;
+ }
+}
+
+
+int main(int argc, char **argv)
+{
+ PRIntn rv;
+
+ PR_STDIO_INIT();
+ rv = PR_Initialize(RealMain, argc, argv, 0);
+ return rv;
+} /* main */
diff --git a/nsprpub/pr/tests/joinuu.c b/nsprpub/pr/tests/joinuu.c
new file mode 100644
index 0000000000..4d30bfa7ce
--- /dev/null
+++ b/nsprpub/pr/tests/joinuu.c
@@ -0,0 +1,179 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/***********************************************************************
+**
+** Name: dbmalloc1.c
+**
+** Description: Join tests user - user
+**
+** Modification History:
+**
+** 19-May-97 AGarcia - separate the four join tests into different unit test modules.
+** AGarcia- Converted the test to accomodate the debug_mode flag.
+** The debug mode will print all of the printfs associated with this test.
+** The regress mode will be the default mode. Since the regress tool limits
+** the output to a one line status:PASS or FAIL,all of the printf statements
+** have been handled with an if (debug_mode) statement.
+** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to
+** recognize the return code from tha main program.
+***********************************************************************/
+
+/***********************************************************************
+** Includes
+***********************************************************************/
+/* Used to get the command line option */
+#include "plgetopt.h"
+
+#include "nspr.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+PRIntn failed_already=0;
+PRIntn debug_mode;
+
+
+/*
+ Program to test joining of threads. Two threads are created. One
+ to be waited upon until it has started. The other to join after it has
+ completed.
+*/
+
+
+static void lowPriority(void *arg)
+{
+}
+
+static void highPriority(void *arg)
+{
+}
+
+void runTest(PRThreadScope scope1, PRThreadScope scope2)
+{
+ PRThread *low,*high;
+
+ /* create the low and high priority threads */
+
+ low = PR_CreateThread(PR_USER_THREAD,
+ lowPriority, 0,
+ PR_PRIORITY_LOW,
+ scope1,
+ PR_JOINABLE_THREAD,
+ 0);
+ if (!low) {
+ if (debug_mode) {
+ printf("\tcannot create low priority thread\n");
+ }
+ else {
+ failed_already=1;
+ }
+ return;
+ }
+
+ high = PR_CreateThread(PR_USER_THREAD,
+ highPriority, 0,
+ PR_PRIORITY_HIGH,
+ scope2,
+ PR_JOINABLE_THREAD,
+ 0);
+ if (!high) {
+ if (debug_mode) {
+ printf("\tcannot create high priority thread\n");
+ }
+ else {
+ failed_already=1;
+ }
+ return;
+ }
+
+ /* Do the joining for both threads */
+ if (PR_JoinThread(low) == PR_FAILURE) {
+ if (debug_mode) {
+ printf("\tcannot join low priority thread\n");
+ }
+ else {
+ failed_already=1;
+ }
+ return;
+ } else {
+ if (debug_mode) {
+ printf("\tjoined low priority thread\n");
+ }
+ }
+ if (PR_JoinThread(high) == PR_FAILURE) {
+ if (debug_mode) {
+ printf("\tcannot join high priority thread\n");
+ }
+ else {
+ failed_already=1;
+ }
+ return;
+ } else {
+ if (debug_mode) {
+ printf("\tjoined high priority thread\n");
+ }
+ }
+}
+
+static PRIntn PR_CALLBACK RealMain( PRIntn argc, char **argv )
+{
+ /* The command line argument: -d is used to determine if the test is being run
+ in debug mode. The regress tool requires only one line output:PASS or FAIL.
+ All of the printfs associated with this test has been handled with a if (debug_mode)
+ test.
+ Usage: test_name -d
+ */
+
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "d:");
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 'd': /* debug mode */
+ debug_mode = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
+ PR_STDIO_INIT();
+
+ /* main test */
+ if (debug_mode) {
+ printf("User-User test\n");
+ }
+ runTest(PR_LOCAL_THREAD, PR_LOCAL_THREAD);
+
+ if(failed_already)
+ {
+ printf("FAIL\n");
+ return 1;
+ } else
+ {
+ printf("PASS\n");
+ return 0;
+ }
+
+
+}
+
+
+int main(int argc, char **argv)
+{
+ PRIntn rv;
+
+ PR_STDIO_INIT();
+ rv = PR_Initialize(RealMain, argc, argv, 0);
+ return rv;
+} /* main */
diff --git a/nsprpub/pr/tests/layer.c b/nsprpub/pr/tests/layer.c
new file mode 100644
index 0000000000..8ad32eeaa8
--- /dev/null
+++ b/nsprpub/pr/tests/layer.c
@@ -0,0 +1,471 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "prio.h"
+#include "prprf.h"
+#include "prlog.h"
+#include "prnetdb.h"
+#include "prthread.h"
+
+#include "plerror.h"
+#include "plgetopt.h"
+#include "prwin16.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+/*
+** Testing layering of I/O
+**
+** The layered server
+** A thread that acts as a server. It creates a TCP listener with a dummy
+** layer pushed on top. Then listens for incoming connections. Each connection
+** request for connection will be layered as well, accept one request, echo
+** it back and close.
+**
+** The layered client
+** Pretty much what you'd expect.
+*/
+
+static PRFileDesc *logFile;
+static PRDescIdentity identity;
+static PRNetAddr server_address;
+
+static PRIOMethods myMethods;
+
+typedef enum Verbosity {silent, quiet, chatty, noisy} Verbosity;
+
+static PRIntn minor_iterations = 5;
+static PRIntn major_iterations = 1;
+static Verbosity verbosity = quiet;
+
+#ifdef DEBUG
+#define PORT_INC_DO +100
+#else
+#define PORT_INC_DO
+#endif
+#ifdef IS_64
+#define PORT_INC_3264 +200
+#else
+#define PORT_INC_3264
+#endif
+
+static PRUint16 default_port = 12273 PORT_INC_DO PORT_INC_3264;
+
+static PRFileDesc *PushLayer(PRFileDesc *stack)
+{
+ PRFileDesc *layer = PR_CreateIOLayerStub(identity, &myMethods);
+ PRStatus rv = PR_PushIOLayer(stack, PR_GetLayersIdentity(stack), layer);
+ if (verbosity > quiet) {
+ PR_fprintf(logFile, "Pushed layer(0x%x) onto stack(0x%x)\n", layer, stack);
+ }
+ PR_ASSERT(PR_SUCCESS == rv);
+ return stack;
+} /* PushLayer */
+
+static PRFileDesc *PushNewLayers(PRFileDesc *stack)
+{
+ PRDescIdentity tmp_identity;
+ PRFileDesc *layer;
+ PRStatus rv;
+
+ /* push a dummy layer */
+ tmp_identity = PR_GetUniqueIdentity("Dummy 1");
+ layer = PR_CreateIOLayerStub(tmp_identity, PR_GetDefaultIOMethods());
+ rv = PR_PushIOLayer(stack, PR_GetLayersIdentity(stack), layer);
+ if (verbosity > quiet)
+ PR_fprintf(logFile, "Pushed layer(0x%x) onto stack(0x%x)\n", layer,
+ stack);
+ PR_ASSERT(PR_SUCCESS == rv);
+
+ /* push a data processing layer */
+ layer = PR_CreateIOLayerStub(identity, &myMethods);
+ rv = PR_PushIOLayer(stack, PR_GetLayersIdentity(stack), layer);
+ if (verbosity > quiet)
+ PR_fprintf(logFile, "Pushed layer(0x%x) onto stack(0x%x)\n", layer,
+ stack);
+ PR_ASSERT(PR_SUCCESS == rv);
+
+ /* push another dummy layer */
+ tmp_identity = PR_GetUniqueIdentity("Dummy 2");
+ layer = PR_CreateIOLayerStub(tmp_identity, PR_GetDefaultIOMethods());
+ rv = PR_PushIOLayer(stack, PR_GetLayersIdentity(stack), layer);
+ if (verbosity > quiet)
+ PR_fprintf(logFile, "Pushed layer(0x%x) onto stack(0x%x)\n", layer,
+ stack);
+ PR_ASSERT(PR_SUCCESS == rv);
+ return stack;
+} /* PushLayer */
+
+#if 0
+static PRFileDesc *PopLayer(PRFileDesc *stack)
+{
+ PRFileDesc *popped = PR_PopIOLayer(stack, identity);
+ if (verbosity > quiet) {
+ PR_fprintf(logFile, "Popped layer(0x%x) from stack(0x%x)\n", popped, stack);
+ }
+ popped->dtor(popped);
+
+ return stack;
+} /* PopLayer */
+#endif
+
+static void PR_CALLBACK Client(void *arg)
+{
+ PRStatus rv;
+ PRUint8 buffer[100];
+ PRIntn empty_flags = 0;
+ PRIntn bytes_read, bytes_sent;
+ PRFileDesc *stack = (PRFileDesc*)arg;
+
+ /* Initialize the buffer so that Purify won't complain */
+ memset(buffer, 0, sizeof(buffer));
+
+ rv = PR_Connect(stack, &server_address, PR_INTERVAL_NO_TIMEOUT);
+ PR_ASSERT(PR_SUCCESS == rv);
+ while (minor_iterations-- > 0)
+ {
+ bytes_sent = PR_Send(
+ stack, buffer, sizeof(buffer), empty_flags, PR_INTERVAL_NO_TIMEOUT);
+ PR_ASSERT(sizeof(buffer) == bytes_sent);
+ if (verbosity > chatty) {
+ PR_fprintf(logFile, "Client sending %d bytes\n", bytes_sent);
+ }
+ bytes_read = PR_Recv(
+ stack, buffer, bytes_sent, empty_flags, PR_INTERVAL_NO_TIMEOUT);
+ if (verbosity > chatty) {
+ PR_fprintf(logFile, "Client receiving %d bytes\n", bytes_read);
+ }
+ PR_ASSERT(bytes_read == bytes_sent);
+ }
+
+ if (verbosity > quiet) {
+ PR_fprintf(logFile, "Client shutting down stack\n");
+ }
+
+ rv = PR_Shutdown(stack, PR_SHUTDOWN_BOTH); PR_ASSERT(PR_SUCCESS == rv);
+} /* Client */
+
+static void PR_CALLBACK Server(void *arg)
+{
+ PRStatus rv;
+ PRUint8 buffer[100];
+ PRFileDesc *service;
+ PRUintn empty_flags = 0;
+ PRIntn bytes_read, bytes_sent;
+ PRFileDesc *stack = (PRFileDesc*)arg;
+ PRNetAddr client_address;
+
+ service = PR_Accept(stack, &client_address, PR_INTERVAL_NO_TIMEOUT);
+ if (verbosity > quiet) {
+ PR_fprintf(logFile, "Server accepting connection\n");
+ }
+
+ do
+ {
+ bytes_read = PR_Recv(
+ service, buffer, sizeof(buffer), empty_flags, PR_INTERVAL_NO_TIMEOUT);
+ if (0 != bytes_read)
+ {
+ if (verbosity > chatty) {
+ PR_fprintf(logFile, "Server receiving %d bytes\n", bytes_read);
+ }
+ PR_ASSERT(bytes_read > 0);
+ bytes_sent = PR_Send(
+ service, buffer, bytes_read, empty_flags, PR_INTERVAL_NO_TIMEOUT);
+ if (verbosity > chatty) {
+ PR_fprintf(logFile, "Server sending %d bytes\n", bytes_sent);
+ }
+ PR_ASSERT(bytes_read == bytes_sent);
+ }
+
+ } while (0 != bytes_read);
+
+ if (verbosity > quiet) {
+ PR_fprintf(logFile, "Server shutting down and closing stack\n");
+ }
+ rv = PR_Shutdown(service, PR_SHUTDOWN_BOTH); PR_ASSERT(PR_SUCCESS == rv);
+ rv = PR_Close(service); PR_ASSERT(PR_SUCCESS == rv);
+
+} /* Server */
+
+static PRInt32 PR_CALLBACK MyRecv(
+ PRFileDesc *fd, void *buf, PRInt32 amount,
+ PRIntn flags, PRIntervalTime timeout)
+{
+ char *b = (char*)buf;
+ PRFileDesc *lo = fd->lower;
+ PRInt32 rv, readin = 0, request = 0;
+ rv = lo->methods->recv(lo, &request, sizeof(request), flags, timeout);
+ if (verbosity > chatty) PR_fprintf(
+ logFile, "MyRecv sending permission for %d bytes\n", request);
+ if (0 < rv)
+ {
+ if (verbosity > chatty) PR_fprintf(
+ logFile, "MyRecv received permission request for %d bytes\n", request);
+ rv = lo->methods->send(
+ lo, &request, sizeof(request), flags, timeout);
+ if (0 < rv)
+ {
+ if (verbosity > chatty) PR_fprintf(
+ logFile, "MyRecv sending permission for %d bytes\n", request);
+ while (readin < request)
+ {
+ rv = lo->methods->recv(
+ lo, b + readin, amount - readin, flags, timeout);
+ if (rv <= 0) {
+ break;
+ }
+ if (verbosity > chatty) PR_fprintf(
+ logFile, "MyRecv received %d bytes\n", rv);
+ readin += rv;
+ }
+ rv = readin;
+ }
+ }
+ return rv;
+} /* MyRecv */
+
+static PRInt32 PR_CALLBACK MySend(
+ PRFileDesc *fd, const void *buf, PRInt32 amount,
+ PRIntn flags, PRIntervalTime timeout)
+{
+ PRFileDesc *lo = fd->lower;
+ const char *b = (const char*)buf;
+ PRInt32 rv, wroteout = 0, request;
+ if (verbosity > chatty) PR_fprintf(
+ logFile, "MySend asking permission to send %d bytes\n", amount);
+ rv = lo->methods->send(lo, &amount, sizeof(amount), flags, timeout);
+ if (0 < rv)
+ {
+ rv = lo->methods->recv(
+ lo, &request, sizeof(request), flags, timeout);
+ if (0 < rv)
+ {
+ PR_ASSERT(request == amount);
+ if (verbosity > chatty) PR_fprintf(
+ logFile, "MySend got permission to send %d bytes\n", request);
+ while (wroteout < request)
+ {
+ rv = lo->methods->send(
+ lo, b + wroteout, request - wroteout, flags, timeout);
+ if (rv <= 0) {
+ break;
+ }
+ if (verbosity > chatty) PR_fprintf(
+ logFile, "MySend wrote %d bytes\n", rv);
+ wroteout += rv;
+ }
+ rv = amount;
+ }
+ }
+ return rv;
+} /* MySend */
+
+static Verbosity ChangeVerbosity(Verbosity verbosity, PRIntn delta)
+{
+ PRIntn verbage = (PRIntn)verbosity + delta;
+ if (verbage < (PRIntn)silent) {
+ verbage = (PRIntn)silent;
+ }
+ else if (verbage > (PRIntn)noisy) {
+ verbage = (PRIntn)noisy;
+ }
+ return (Verbosity)verbage;
+} /* ChangeVerbosity */
+
+int main(int argc, char **argv)
+{
+ PRStatus rv;
+ PRIntn mits;
+ PLOptStatus os;
+ PRFileDesc *client, *service;
+ PRFileDesc *client_stack, *service_stack;
+ PRNetAddr any_address;
+ const char *server_name = NULL;
+ const PRIOMethods *stubMethods;
+ PRThread *client_thread, *server_thread;
+ PRThreadScope thread_scope = PR_LOCAL_THREAD;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "dqGC:c:p:");
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 0:
+ server_name = opt->value;
+ break;
+ case 'd': /* debug mode */
+ if (verbosity < noisy) {
+ verbosity = ChangeVerbosity(verbosity, 1);
+ }
+ break;
+ case 'q': /* debug mode */
+ if (verbosity > silent) {
+ verbosity = ChangeVerbosity(verbosity, -1);
+ }
+ break;
+ case 'G': /* use global threads */
+ thread_scope = PR_GLOBAL_THREAD;
+ break;
+ case 'C': /* number of threads waiting */
+ major_iterations = atoi(opt->value);
+ break;
+ case 'c': /* number of client threads */
+ minor_iterations = atoi(opt->value);
+ break;
+ case 'p': /* default port */
+ default_port = atoi(opt->value);
+ break;
+ default:
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+ PR_STDIO_INIT();
+
+ logFile = PR_GetSpecialFD(PR_StandardError);
+
+ identity = PR_GetUniqueIdentity("Dummy");
+ stubMethods = PR_GetDefaultIOMethods();
+
+ /*
+ ** The protocol we're going to implement is one where in order to initiate
+ ** a send, the sender must first solicit permission. Therefore, every
+ ** send is really a send - receive - send sequence.
+ */
+ myMethods = *stubMethods; /* first get the entire batch */
+ myMethods.recv = MyRecv; /* then override the ones we care about */
+ myMethods.send = MySend; /* then override the ones we care about */
+
+ if (NULL == server_name)
+ rv = PR_InitializeNetAddr(
+ PR_IpAddrLoopback, default_port, &server_address);
+ else
+ {
+ rv = PR_StringToNetAddr(server_name, &server_address);
+ PR_ASSERT(PR_SUCCESS == rv);
+ rv = PR_InitializeNetAddr(
+ PR_IpAddrNull, default_port, &server_address);
+ }
+ PR_ASSERT(PR_SUCCESS == rv);
+
+ /* one type w/o layering */
+
+ mits = minor_iterations;
+ while (major_iterations-- > 0)
+ {
+ if (verbosity > silent) {
+ PR_fprintf(logFile, "Beginning non-layered test\n");
+ }
+ client = PR_NewTCPSocket(); PR_ASSERT(NULL != client);
+ service = PR_NewTCPSocket(); PR_ASSERT(NULL != service);
+ rv = PR_InitializeNetAddr(PR_IpAddrAny, default_port, &any_address);
+ PR_ASSERT(PR_SUCCESS == rv);
+ rv = PR_Bind(service, &any_address); PR_ASSERT(PR_SUCCESS == rv);
+ rv = PR_Listen(service, 10); PR_ASSERT(PR_SUCCESS == rv);
+
+ minor_iterations = mits;
+ server_thread = PR_CreateThread(
+ PR_USER_THREAD, Server, service,
+ PR_PRIORITY_HIGH, thread_scope,
+ PR_JOINABLE_THREAD, 16 * 1024);
+ PR_ASSERT(NULL != server_thread);
+
+ client_thread = PR_CreateThread(
+ PR_USER_THREAD, Client, client,
+ PR_PRIORITY_NORMAL, thread_scope,
+ PR_JOINABLE_THREAD, 16 * 1024);
+ PR_ASSERT(NULL != client_thread);
+
+ rv = PR_JoinThread(client_thread);
+ PR_ASSERT(PR_SUCCESS == rv);
+ rv = PR_JoinThread(server_thread);
+ PR_ASSERT(PR_SUCCESS == rv);
+
+ rv = PR_Close(client); PR_ASSERT(PR_SUCCESS == rv);
+ rv = PR_Close(service); PR_ASSERT(PR_SUCCESS == rv);
+ if (verbosity > silent) {
+ PR_fprintf(logFile, "Ending non-layered test\n");
+ }
+
+ /* with layering */
+ if (verbosity > silent) {
+ PR_fprintf(logFile, "Beginning layered test\n");
+ }
+ client = PR_NewTCPSocket(); PR_ASSERT(NULL != client);
+ PushLayer(client);
+ service = PR_NewTCPSocket(); PR_ASSERT(NULL != service);
+ PushLayer(service);
+ rv = PR_InitializeNetAddr(PR_IpAddrAny, default_port, &any_address);
+ PR_ASSERT(PR_SUCCESS == rv);
+ rv = PR_Bind(service, &any_address); PR_ASSERT(PR_SUCCESS == rv);
+ rv = PR_Listen(service, 10); PR_ASSERT(PR_SUCCESS == rv);
+
+ minor_iterations = mits;
+ server_thread = PR_CreateThread(
+ PR_USER_THREAD, Server, service,
+ PR_PRIORITY_HIGH, thread_scope,
+ PR_JOINABLE_THREAD, 16 * 1024);
+ PR_ASSERT(NULL != server_thread);
+
+ client_thread = PR_CreateThread(
+ PR_USER_THREAD, Client, client,
+ PR_PRIORITY_NORMAL, thread_scope,
+ PR_JOINABLE_THREAD, 16 * 1024);
+ PR_ASSERT(NULL != client_thread);
+
+ rv = PR_JoinThread(client_thread);
+ PR_ASSERT(PR_SUCCESS == rv);
+ rv = PR_JoinThread(server_thread);
+ PR_ASSERT(PR_SUCCESS == rv);
+
+ rv = PR_Close(client); PR_ASSERT(PR_SUCCESS == rv);
+ rv = PR_Close(service); PR_ASSERT(PR_SUCCESS == rv);
+ /* with layering, using new style stack */
+ if (verbosity > silent)
+ PR_fprintf(logFile,
+ "Beginning layered test with new style stack\n");
+ client = PR_NewTCPSocket(); PR_ASSERT(NULL != client);
+ client_stack = PR_CreateIOLayer(client);
+ PushNewLayers(client_stack);
+ service = PR_NewTCPSocket(); PR_ASSERT(NULL != service);
+ service_stack = PR_CreateIOLayer(service);
+ PushNewLayers(service_stack);
+ rv = PR_InitializeNetAddr(PR_IpAddrAny, default_port, &any_address);
+ PR_ASSERT(PR_SUCCESS == rv);
+ rv = PR_Bind(service, &any_address); PR_ASSERT(PR_SUCCESS == rv);
+ rv = PR_Listen(service, 10); PR_ASSERT(PR_SUCCESS == rv);
+
+ minor_iterations = mits;
+ server_thread = PR_CreateThread(
+ PR_USER_THREAD, Server, service_stack,
+ PR_PRIORITY_HIGH, thread_scope,
+ PR_JOINABLE_THREAD, 16 * 1024);
+ PR_ASSERT(NULL != server_thread);
+
+ client_thread = PR_CreateThread(
+ PR_USER_THREAD, Client, client_stack,
+ PR_PRIORITY_NORMAL, thread_scope,
+ PR_JOINABLE_THREAD, 16 * 1024);
+ PR_ASSERT(NULL != client_thread);
+
+ rv = PR_JoinThread(client_thread);
+ PR_ASSERT(PR_SUCCESS == rv);
+ rv = PR_JoinThread(server_thread);
+ PR_ASSERT(PR_SUCCESS == rv);
+
+ rv = PR_Close(client_stack); PR_ASSERT(PR_SUCCESS == rv);
+ rv = PR_Close(service_stack); PR_ASSERT(PR_SUCCESS == rv);
+ if (verbosity > silent) {
+ PR_fprintf(logFile, "Ending layered test\n");
+ }
+ }
+ return 0;
+} /* main */
+
+/* layer.c */
diff --git a/nsprpub/pr/tests/lazyinit.c b/nsprpub/pr/tests/lazyinit.c
new file mode 100644
index 0000000000..2a910f2051
--- /dev/null
+++ b/nsprpub/pr/tests/lazyinit.c
@@ -0,0 +1,108 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+** File: lazyinit.c
+** Description: Testing lazy initialization
+**
+** Since you only get to initialize once, you have to rerun the test
+** for each test case. The test cases are numbered. If you want to
+** add more tests, take the next number and add it to the switch
+** statement.
+**
+** This test is problematic on systems that don't support the notion
+** of console output. The workarounds to emulate that feature include
+** initializations themselves, which defeats the purpose here.
+*/
+
+#include "prcvar.h"
+#include "prenv.h"
+#include "prinit.h"
+#include "prinrval.h"
+#include "prio.h"
+#include "prlock.h"
+#include "prlog.h"
+#include "prthread.h"
+#include "prtypes.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+static void PR_CALLBACK lazyEntry(void *arg)
+{
+ PR_ASSERT(NULL == arg);
+} /* lazyEntry */
+
+
+int main(int argc, char **argv)
+{
+ PRUintn pdkey;
+ PRStatus status;
+ char *path = NULL;
+ PRDir *dir = NULL;
+ PRLock *ml = NULL;
+ PRCondVar *cv = NULL;
+ PRThread *thread = NULL;
+ PRIntervalTime interval = 0;
+ PRFileDesc *file, *udp, *tcp, *pair[2];
+ PRIntn test;
+
+ if ( argc < 2)
+ {
+ test = 0;
+ }
+ else {
+ test = atoi(argv[1]);
+ }
+
+ switch (test)
+ {
+ case 0: ml = PR_NewLock();
+ break;
+
+ case 1: interval = PR_SecondsToInterval(1);
+ break;
+
+ case 2: thread = PR_CreateThread(
+ PR_USER_THREAD, lazyEntry, NULL, PR_PRIORITY_NORMAL,
+ PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0);
+ break;
+
+ case 3: file = PR_Open("./tmp-", PR_RDONLY, 0);
+ break;
+
+ case 4: udp = PR_NewUDPSocket();
+ break;
+
+ case 5: tcp = PR_NewTCPSocket();
+ break;
+
+ case 6: dir = PR_OpenDir("./tmp-");
+ break;
+
+ case 7: (void)PR_NewThreadPrivateIndex(&pdkey, NULL);
+ break;
+
+ case 8: path = PR_GetEnv("PATH");
+ break;
+
+ case 9: status = PR_NewTCPSocketPair(pair);
+ break;
+
+ case 10: PR_SetConcurrency(2);
+ break;
+
+ default:
+ printf(
+ "lazyinit: unrecognized command line argument: %s\n",
+ argv[1] );
+ printf( "FAIL\n" );
+ exit( 1 );
+ break;
+ } /* switch() */
+ return 0;
+} /* Lazy */
+
+/* lazyinit.c */
diff --git a/nsprpub/pr/tests/libfilename.c b/nsprpub/pr/tests/libfilename.c
new file mode 100644
index 0000000000..09d0980de3
--- /dev/null
+++ b/nsprpub/pr/tests/libfilename.c
@@ -0,0 +1,101 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/***********************************************************************
+**
+** Name: libfilename.c
+**
+** Description: test PR_GetLibraryFilePathname.
+**
+***********************************************************************/
+
+#include "nspr.h"
+#include "pprio.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+PRBool debug_mode = PR_FALSE;
+
+static PRStatus RunTest(const char *name, PRFuncPtr addr)
+{
+ char *pathname;
+ PRFileDesc *fd;
+
+ pathname = PR_GetLibraryFilePathname(name, addr);
+ if (pathname == NULL) {
+ fprintf(stderr, "PR_GetLibraryFilePathname failed\n");
+ /* we let this test pass if this function is not implemented */
+ if (PR_GetError() == PR_NOT_IMPLEMENTED_ERROR) {
+ return PR_SUCCESS;
+ }
+ return PR_FAILURE;
+ }
+
+ if (debug_mode) {
+ printf("Pathname is %s\n", pathname);
+ }
+ fd = PR_OpenFile(pathname, PR_RDONLY, 0);
+ if (fd == NULL) {
+ fprintf(stderr, "PR_Open failed: %d\n", (int)PR_GetError());
+ return PR_FAILURE;
+ }
+ if (PR_Close(fd) == PR_FAILURE) {
+ fprintf(stderr, "PR_Close failed: %d\n", (int)PR_GetError());
+ return PR_FAILURE;
+ }
+ PR_Free(pathname);
+ return PR_SUCCESS;
+}
+
+int main(int argc, char **argv)
+{
+ char *name;
+ PRFuncPtr addr;
+ PRLibrary *lib;
+ PRBool failed = PR_FALSE;
+
+ if (argc >= 2 && strcmp(argv[1], "-d") == 0) {
+ debug_mode = PR_TRUE;
+ }
+
+ /* First test a library that is implicitly linked. */
+#ifdef WINNT
+ name = PR_Malloc(strlen("libnspr4.dll")+1);
+ strcpy(name, "libnspr4.dll");
+#else
+ name = PR_GetLibraryName(NULL, "nspr4");
+#endif
+ addr = (PRFuncPtr)PR_GetTCPMethods()->close;
+ if (RunTest(name, addr) == PR_FAILURE) {
+ failed = PR_TRUE;
+ }
+ PR_FreeLibraryName(name);
+
+ /* Next test a library that is dynamically loaded. */
+ name = PR_GetLibraryName("dll", "my");
+ if (debug_mode) {
+ printf("Loading library %s\n", name);
+ }
+ lib = PR_LoadLibrary(name);
+ if (!lib) {
+ fprintf(stderr, "PR_LoadLibrary failed\n");
+ exit(1);
+ }
+ PR_FreeLibraryName(name);
+ name = PR_GetLibraryName(NULL, "my");
+ addr = PR_FindFunctionSymbol(lib, "My_GetValue");
+ if (RunTest(name, addr) == PR_FAILURE) {
+ failed = PR_TRUE;
+ }
+ PR_FreeLibraryName(name);
+ PR_UnloadLibrary(lib);
+ if (failed) {
+ printf("FAIL\n");
+ return 1;
+ }
+ printf("PASS\n");
+ return 0;
+}
diff --git a/nsprpub/pr/tests/lltest.c b/nsprpub/pr/tests/lltest.c
new file mode 100644
index 0000000000..26f7d8eadf
--- /dev/null
+++ b/nsprpub/pr/tests/lltest.c
@@ -0,0 +1,969 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+** testll.c -- test suite for 64bit integer (longlong) operations
+**
+** Summary: testll [-d] | [-h]
+**
+** Where:
+** -d set debug mode on; displays individual test failures
+** -v verbose mode; displays progress in test, plus -d
+** -h gives usage message.
+**
+** Description:
+** lltest.c tests the functions defined in NSPR 2.0's prlong.h.
+**
+** Successive tests begin to depend on other LL functions working
+** correctly. So, ... Do not change the order of the tests as run
+** from main().
+**
+** Caveats:
+** Do not even begin to think that this is an exhaustive test!
+**
+** These tests try a little of everything, but not all boundary
+** conditions and limits are tested.
+** You want better coverage? ... Add it.
+**
+** ---
+** Author: Lawrence Hardiman <larryh@netscape.com>.
+** ---
+** Revision History:
+** 01-Oct-1997. Original implementation.
+**
+*/
+
+#include "nspr.h"
+#include "plgetopt.h"
+
+/* --- Local Definitions --- */
+#define ReportProgress(m) if (verboseMode) PR_fprintf(output, (m));
+
+
+/* --- Global variables --- */
+static PRIntn failedAlready = 0;
+static PRFileDesc* output = NULL;
+static PRBool debugMode = PR_FALSE;
+static PRBool verboseMode = PR_FALSE;
+
+/*
+** Constants used in tests.
+*/
+const PRInt64 bigZero = LL_INIT( 0, 0 );
+const PRInt64 bigOne = LL_INIT( 0, 1 );
+const PRInt64 bigTwo = LL_INIT( 0, 2 );
+const PRInt64 bigSixTeen = LL_INIT( 0, 16 );
+const PRInt64 bigThirtyTwo = LL_INIT( 0, 32 );
+const PRInt64 bigMinusOne = LL_INIT( 0xffffffff, 0xffffffff );
+const PRInt64 bigMinusTwo = LL_INIT( 0xffffffff, 0xfffffffe );
+const PRInt64 bigNumber = LL_INIT( 0x7fffffff, 0xffffffff );
+const PRInt64 bigMinusNumber = LL_INIT( 0x80000000, 0x00000001 );
+const PRInt64 bigMaxInt32 = LL_INIT( 0x00000000, 0x7fffffff );
+const PRInt64 big2To31 = LL_INIT( 0x00000000, 0x80000000 );
+const PRUint64 bigZeroFox = LL_INIT( 0x00000000, 0xffffffff );
+const PRUint64 bigFoxFox = LL_INIT( 0xffffffff, 0xffffffff );
+const PRUint64 bigFoxZero = LL_INIT( 0xffffffff, 0x00000000 );
+const PRUint64 bigEightZero = LL_INIT( 0x80000000, 0x00000000 );
+const PRUint64 big64K = LL_INIT( 0x00000000, 0x00010000 );
+const PRInt64 bigInt0 = LL_INIT( 0x01a00000, 0x00001000 );
+const PRInt64 bigInt1 = LL_INIT( 0x01a00000, 0x00001100 );
+const PRInt64 bigInt2 = LL_INIT( 0x01a00000, 0x00000100 );
+const PRInt64 bigInt3 = LL_INIT( 0x01a00001, 0x00001000 );
+const PRInt64 bigInt4 = LL_INIT( 0x01a00001, 0x00001100 );
+const PRInt64 bigInt5 = LL_INIT( 0x01a00001, 0x00000100 );
+const PRInt64 bigInt6 = LL_INIT( 0xb1a00000, 0x00001000 );
+const PRInt64 bigInt7 = LL_INIT( 0xb1a00000, 0x00001100 );
+const PRInt64 bigInt8 = LL_INIT( 0xb1a00000, 0x00000100 );
+const PRInt64 bigInt9 = LL_INIT( 0xb1a00001, 0x00001000 );
+const PRInt64 bigInt10 = LL_INIT( 0xb1a00001, 0x00001100 );
+const PRInt64 bigInt11 = LL_INIT( 0xb1a00001, 0x00000100 );
+const PRInt32 one = 1l;
+const PRInt32 minusOne = -1l;
+const PRInt32 sixteen = 16l;
+const PRInt32 thirtyTwo = 32l;
+const PRInt32 sixtyThree = 63l;
+
+/*
+** SetFailed() -- Report individual test failure
+**
+*/
+static void
+SetFailed( char *what, char *how )
+{
+ failedAlready = 1;
+ if ( debugMode ) {
+ PR_fprintf(output, "%s: failed: %s\n", what, how );
+ }
+ return;
+}
+
+static void
+ResultFailed( char *what, char *how, PRInt64 expected, PRInt64 got)
+{
+ if ( debugMode)
+ {
+ SetFailed( what, how );
+ PR_fprintf(output, "Expected: 0x%llx Got: 0x%llx\n", expected, got );
+ }
+ return;
+}
+
+
+/*
+** TestAssignment() -- Test the assignment
+*/
+static void TestAssignment( void )
+{
+ PRInt64 zero = LL_Zero();
+ PRInt64 min = LL_MinInt();
+ PRInt64 max = LL_MaxInt();
+ if (!LL_EQ(zero, bigZero)) {
+ SetFailed("LL_EQ(zero, bigZero)", "!=");
+ }
+ if (!LL_CMP(max, >, min)) {
+ SetFailed("LL_CMP(max, >, min)", "!>");
+ }
+}
+
+/*
+** TestComparisons() -- Test the longlong comparison operations
+*/
+static void
+TestComparisons( void )
+{
+ ReportProgress("Testing Comparisons Operations\n");
+
+ /* test for zero */
+ if ( !LL_IS_ZERO( bigZero )) {
+ SetFailed( "LL_IS_ZERO", "Zero is not zero" );
+ }
+
+ if ( LL_IS_ZERO( bigOne )) {
+ SetFailed( "LL_IS_ZERO", "One tests as zero" );
+ }
+
+ if ( LL_IS_ZERO( bigMinusOne )) {
+ SetFailed( "LL_IS_ZERO", "Minus One tests as zero" );
+ }
+
+ /* test equal */
+ if ( !LL_EQ( bigZero, bigZero )) {
+ SetFailed( "LL_EQ", "zero EQ zero");
+ }
+
+ if ( !LL_EQ( bigOne, bigOne )) {
+ SetFailed( "LL_EQ", "one EQ one" );
+ }
+
+ if ( !LL_EQ( bigNumber, bigNumber )) {
+ SetFailed( "LL_EQ", "bigNumber EQ bigNumber" );
+ }
+
+ if ( !LL_EQ( bigMinusOne, bigMinusOne )) {
+ SetFailed( "LL_EQ", "minus one EQ minus one");
+ }
+
+ if ( LL_EQ( bigZero, bigOne )) {
+ SetFailed( "LL_EQ", "zero EQ one");
+ }
+
+ if ( LL_EQ( bigOne, bigZero )) {
+ SetFailed( "LL_EQ", "one EQ zero" );
+ }
+
+ if ( LL_EQ( bigMinusOne, bigOne )) {
+ SetFailed( "LL_EQ", "minus one EQ one");
+ }
+
+ if ( LL_EQ( bigNumber, bigOne )) {
+ SetFailed( "LL_EQ", "bigNumber EQ one");
+ }
+
+ /* test not equal */
+ if ( LL_NE( bigZero, bigZero )) {
+ SetFailed( "LL_NE", "0 NE 0");
+ }
+
+ if ( LL_NE( bigOne, bigOne )) {
+ SetFailed( "LL_NE", "1 NE 1");
+ }
+
+ if ( LL_NE( bigMinusOne, bigMinusOne )) {
+ SetFailed( "LL_NE", "-1 NE -1");
+ }
+
+ if ( LL_NE( bigNumber, bigNumber )) {
+ SetFailed( "LL_NE", "n NE n");
+ }
+
+ if ( LL_NE( bigMinusNumber, bigMinusNumber )) {
+ SetFailed( "LL_NE", "-n NE -n");
+ }
+
+ if ( !LL_NE( bigZero, bigOne)) {
+ SetFailed( "LL_NE", "0 NE 1");
+ }
+
+ if ( !LL_NE( bigOne, bigMinusNumber)) {
+ SetFailed( "LL_NE", "1 NE -n");
+ }
+
+ /* Greater than or equal to zero */
+ if ( !LL_GE_ZERO( bigZero )) {
+ SetFailed( "LL_GE_ZERO", "0");
+ }
+
+ if ( !LL_GE_ZERO( bigOne )) {
+ SetFailed( "LL_GE_ZERO", "1");
+ }
+
+ if ( !LL_GE_ZERO( bigNumber )) {
+ SetFailed( "LL_GE_ZERO", "n");
+ }
+
+ if ( LL_GE_ZERO( bigMinusOne )) {
+ SetFailed( "LL_GE_ZERO", "-1");
+ }
+
+ if ( LL_GE_ZERO( bigMinusNumber )) {
+ SetFailed( "LL_GE_ZERO", "-n");
+ }
+
+ /* Algebraic Compare two values */
+ if ( !LL_CMP( bigZero, ==, bigZero )) {
+ SetFailed( "LL_CMP", "0 == 0");
+ }
+
+ if ( LL_CMP( bigZero, >, bigZero )) {
+ SetFailed( "LL_CMP", "0 > 0");
+ }
+
+ if ( LL_CMP( bigZero, <, bigZero )) {
+ SetFailed( "LL_CMP", "0 < 0");
+ }
+
+ if ( LL_CMP( bigNumber, <, bigOne )) {
+ SetFailed( "LL_CMP", "n < 1");
+ }
+
+ if ( !LL_CMP( bigNumber, >, bigOne )) {
+ SetFailed( "LL_CMP", "n <= 1");
+ }
+
+ if ( LL_CMP( bigOne, >, bigNumber )) {
+ SetFailed( "LL_CMP", "1 > n");
+ }
+
+ if ( LL_CMP( bigMinusNumber, >, bigNumber )) {
+ SetFailed( "LL_CMP", "-n > n");
+ }
+
+ if ( LL_CMP( bigNumber, !=, bigNumber)) {
+ SetFailed( "LL_CMP", "n != n");
+ }
+
+ if ( !LL_CMP( bigMinusOne, >, bigMinusTwo )) {
+ SetFailed( "LL_CMP", "-1 <= -2");
+ }
+
+ if ( !LL_CMP( bigMaxInt32, <, big2To31 )) {
+ SetFailed( "LL_CMP", "Max 32-bit signed int >= 2^31");
+ }
+
+ /* Two positive numbers */
+ if ( !LL_CMP( bigInt0, <=, bigInt0 )) {
+ SetFailed( "LL_CMP", "LL_CMP(<=) failed");
+ }
+
+ if ( !LL_CMP( bigInt0, <=, bigInt1 )) {
+ SetFailed( "LL_CMP", "LL_CMP(<=) failed");
+ }
+
+ if ( LL_CMP( bigInt0, <=, bigInt2 )) {
+ SetFailed( "LL_CMP", "LL_CMP(<=) failed");
+ }
+
+ if ( !LL_CMP( bigInt0, <=, bigInt3 )) {
+ SetFailed( "LL_CMP", "LL_CMP(<=) failed");
+ }
+
+ if ( !LL_CMP( bigInt0, <=, bigInt4 )) {
+ SetFailed( "LL_CMP", "LL_CMP(<=) failed");
+ }
+
+ if ( !LL_CMP( bigInt0, <=, bigInt5 )) {
+ SetFailed( "LL_CMP", "LL_CMP(<=) failed");
+ }
+
+ /* Two negative numbers */
+ if ( !LL_CMP( bigInt6, <=, bigInt6 )) {
+ SetFailed( "LL_CMP", "LL_CMP(<=) failed");
+ }
+
+ if ( !LL_CMP( bigInt6, <=, bigInt7 )) {
+ SetFailed( "LL_CMP", "LL_CMP(<=) failed");
+ }
+
+ if ( LL_CMP( bigInt6, <=, bigInt8 )) {
+ SetFailed( "LL_CMP", "LL_CMP(<=) failed");
+ }
+
+ if ( !LL_CMP( bigInt6, <=, bigInt9 )) {
+ SetFailed( "LL_CMP", "LL_CMP(<=) failed");
+ }
+
+ if ( !LL_CMP( bigInt6, <=, bigInt10 )) {
+ SetFailed( "LL_CMP", "LL_CMP(<=) failed");
+ }
+
+ if ( !LL_CMP( bigInt6, <=, bigInt11 )) {
+ SetFailed( "LL_CMP", "LL_CMP(<=) failed");
+ }
+
+ /* One positive, one negative */
+ if ( LL_CMP( bigInt0, <=, bigInt6 )) {
+ SetFailed( "LL_CMP", "LL_CMP(<=) failed");
+ }
+
+ if ( LL_CMP( bigInt0, <=, bigInt7 )) {
+ SetFailed( "LL_CMP", "LL_CMP(<=) failed");
+ }
+
+ if ( LL_CMP( bigInt0, <=, bigInt8 )) {
+ SetFailed( "LL_CMP", "LL_CMP(<=) failed");
+ }
+
+ /* Bitwise Compare two numbers */
+ if ( !LL_UCMP( bigZero, ==, bigZero )) {
+ SetFailed( "LL_UCMP", "0 == 0");
+ }
+
+ if ( LL_UCMP( bigZero, >, bigZero )) {
+ SetFailed( "LL_UCMP", "0 > 0");
+ }
+
+ if ( LL_UCMP( bigZero, <, bigZero )) {
+ SetFailed( "LL_UCMP", "0 < 0");
+ }
+
+ if ( LL_UCMP( bigNumber, <, bigOne )) {
+ SetFailed( "LL_UCMP", "n < 1");
+ }
+
+ if ( !LL_UCMP( bigNumber, >, bigOne )) {
+ SetFailed( "LL_UCMP", "n < 1");
+ }
+
+ if ( LL_UCMP( bigOne, >, bigNumber )) {
+ SetFailed( "LL_UCMP", "1 > n");
+ }
+
+ if ( LL_UCMP( bigMinusNumber, <, bigNumber )) {
+ SetFailed( "LL_UCMP", "-n < n");
+ }
+
+ /* Two positive numbers */
+ if ( !LL_UCMP( bigInt0, <=, bigInt0 )) {
+ SetFailed( "LL_UCMP", "LL_UCMP(<=) failed");
+ }
+
+ if ( !LL_UCMP( bigInt0, <=, bigInt1 )) {
+ SetFailed( "LL_UCMP", "LL_UCMP(<=) failed");
+ }
+
+ if ( LL_UCMP( bigInt0, <=, bigInt2 )) {
+ SetFailed( "LL_UCMP", "LL_UCMP(<=) failed");
+ }
+
+ if ( !LL_UCMP( bigInt0, <=, bigInt3 )) {
+ SetFailed( "LL_UCMP", "LL_UCMP(<=) failed");
+ }
+
+ if ( !LL_UCMP( bigInt0, <=, bigInt4 )) {
+ SetFailed( "LL_UCMP", "LL_UCMP(<=) failed");
+ }
+
+ if ( !LL_UCMP( bigInt0, <=, bigInt5 )) {
+ SetFailed( "LL_UCMP", "LL_UCMP(<=) failed");
+ }
+
+ /* Two negative numbers */
+ if ( !LL_UCMP( bigInt6, <=, bigInt6 )) {
+ SetFailed( "LL_UCMP", "LL_UCMP(<=) failed");
+ }
+
+ if ( !LL_UCMP( bigInt6, <=, bigInt7 )) {
+ SetFailed( "LL_UCMP", "LL_UCMP(<=) failed");
+ }
+
+ if ( LL_UCMP( bigInt6, <=, bigInt8 )) {
+ SetFailed( "LL_UCMP", "LL_UCMP(<=) failed");
+ }
+
+ if ( !LL_UCMP( bigInt6, <=, bigInt9 )) {
+ SetFailed( "LL_UCMP", "LL_UCMP(<=) failed");
+ }
+
+ if ( !LL_UCMP( bigInt6, <=, bigInt10 )) {
+ SetFailed( "LL_UCMP", "LL_UCMP(<=) failed");
+ }
+
+ if ( !LL_UCMP( bigInt6, <=, bigInt11 )) {
+ SetFailed( "LL_UCMP", "LL_UCMP(<=) failed");
+ }
+
+ /* One positive, one negative */
+ if ( !LL_UCMP( bigInt0, <=, bigInt6 )) {
+ SetFailed( "LL_UCMP", "LL_UCMP(<=) failed");
+ }
+
+ if ( !LL_UCMP( bigInt0, <=, bigInt7 )) {
+ SetFailed( "LL_UCMP", "LL_UCMP(<=) failed");
+ }
+
+ if ( !LL_UCMP( bigInt0, <=, bigInt8 )) {
+ SetFailed( "LL_UCMP", "LL_UCMP(<=) failed");
+ }
+
+ return;
+}
+
+/*
+** TestLogicalOperations() -- Tests for AND, OR, ...
+**
+*/
+static void
+TestLogicalOperations( void )
+{
+ PRUint64 result, result2;
+
+ ReportProgress("Testing Logical Operations\n");
+
+ /* Test AND */
+ LL_AND( result, bigZero, bigZero );
+ if ( !LL_IS_ZERO( result )) {
+ ResultFailed( "LL_AND", "0 & 0", bigZero, result );
+ }
+
+ LL_AND( result, bigOne, bigOne );
+ if ( LL_IS_ZERO( result )) {
+ ResultFailed( "LL_AND", "1 & 1", bigOne, result );
+ }
+
+ LL_AND( result, bigZero, bigOne );
+ if ( !LL_IS_ZERO( result )) {
+ ResultFailed( "LL_AND", "1 & 1", bigZero, result );
+ }
+
+ LL_AND( result, bigMinusOne, bigMinusOne );
+ if ( !LL_UCMP( result, ==, bigMinusOne )) {
+ ResultFailed( "LL_AND", "-1 & -1", bigMinusOne, result );
+ }
+
+ /* test OR */
+ LL_OR( result, bigZero, bigZero );
+ if ( !LL_IS_ZERO( result )) {
+ ResultFailed( "LL_OR", "0 | 1", bigZero, result);
+ }
+
+ LL_OR( result, bigZero, bigOne );
+ if ( LL_IS_ZERO( result )) {
+ ResultFailed( "LL_OR", "0 | 1", bigOne, result );
+ }
+
+ LL_OR( result, bigZero, bigMinusNumber );
+ if ( !LL_UCMP( result, ==, bigMinusNumber )) {
+ ResultFailed( "LL_OR", "0 | -n", bigMinusNumber, result);
+ }
+
+ LL_OR( result, bigMinusNumber, bigZero );
+ if ( !LL_UCMP( result, ==, bigMinusNumber )) {
+ ResultFailed( "LL_OR", "-n | 0", bigMinusNumber, result );
+ }
+
+ /* test XOR */
+ LL_XOR( result, bigZero, bigZero );
+ if ( LL_UCMP( result, !=, bigZero )) {
+ ResultFailed( "LL_XOR", "0 ^ 0", bigZero, result);
+ }
+
+ LL_XOR( result, bigOne, bigZero );
+ if ( LL_UCMP( result, !=, bigOne )) {
+ ResultFailed( "LL_XOR", "1 ^ 0", bigZero, result );
+ }
+
+ LL_XOR( result, bigMinusNumber, bigZero );
+ if ( LL_UCMP( result, !=, bigMinusNumber )) {
+ ResultFailed( "LL_XOR", "-n ^ 0", bigMinusNumber, result );
+ }
+
+ LL_XOR( result, bigMinusNumber, bigMinusNumber );
+ if ( LL_UCMP( result, !=, bigZero )) {
+ ResultFailed( "LL_XOR", "-n ^ -n", bigMinusNumber, result);
+ }
+
+ /* test OR2. */
+ result = bigZero;
+ LL_OR2( result, bigOne );
+ if ( LL_UCMP( result, !=, bigOne )) {
+ ResultFailed( "LL_OR2", "(r=0) |= 1", bigOne, result);
+ }
+
+ result = bigOne;
+ LL_OR2( result, bigNumber );
+ if ( LL_UCMP( result, !=, bigNumber )) {
+ ResultFailed( "LL_OR2", "(r=1) |= n", bigNumber, result);
+ }
+
+ result = bigMinusNumber;
+ LL_OR2( result, bigMinusNumber );
+ if ( LL_UCMP( result, !=, bigMinusNumber )) {
+ ResultFailed( "LL_OR2", "(r=-n) |= -n", bigMinusNumber, result);
+ }
+
+ /* test NOT */
+ LL_NOT( result, bigMinusNumber);
+ LL_NOT( result2, result);
+ if ( LL_UCMP( result2, !=, bigMinusNumber )) {
+ ResultFailed( "LL_NOT", "r != ~(~-n)", bigMinusNumber, result);
+ }
+
+ /* test Negation */
+ LL_NEG( result, bigMinusNumber );
+ LL_NEG( result2, result );
+ if ( LL_CMP( result2, !=, bigMinusNumber )) {
+ ResultFailed( "LL_NEG", "r != -(-(-n))", bigMinusNumber, result);
+ }
+
+ return;
+}
+
+
+
+/*
+** TestConversion() -- Test Conversion Operations
+**
+*/
+static void
+TestConversion( void )
+{
+ PRInt64 result;
+ PRInt64 resultU;
+ PRInt32 result32;
+ PRUint32 resultU32;
+ float resultF;
+ PRFloat64 resultD;
+
+ ReportProgress("Testing Conversion Operations\n");
+
+ /* LL_L2I -- Convert to signed 32bit */
+ LL_L2I(result32, bigOne );
+ if ( result32 != one ) {
+ SetFailed( "LL_L2I", "r != 1");
+ }
+
+ LL_L2I(result32, bigMinusOne );
+ if ( result32 != minusOne ) {
+ SetFailed( "LL_L2I", "r != -1");
+ }
+
+ /* LL_L2UI -- Convert 64bit to unsigned 32bit */
+ LL_L2UI( resultU32, bigMinusOne );
+ if ( resultU32 != (PRUint32) minusOne ) {
+ SetFailed( "LL_L2UI", "r != -1");
+ }
+
+ LL_L2UI( resultU32, bigOne );
+ if ( resultU32 != (PRUint32) one ) {
+ SetFailed( "LL_L2UI", "r != 1");
+ }
+
+ /* LL_L2F -- Convert to 32bit floating point */
+ LL_L2F( resultF, bigOne );
+ if ( resultF != 1.0 ) {
+ SetFailed( "LL_L2F", "r != 1.0");
+ }
+
+ LL_L2F( resultF, bigMinusOne );
+ if ( resultF != -1.0 ) {
+ SetFailed( "LL_L2F", "r != 1.0");
+ }
+
+ /* LL_L2D -- Convert to 64bit floating point */
+ LL_L2D( resultD, bigOne );
+ if ( resultD != 1.0L ) {
+ SetFailed( "LL_L2D", "r != 1.0");
+ }
+
+ LL_L2D( resultD, bigMinusOne );
+ if ( resultD != -1.0L ) {
+ SetFailed( "LL_L2D", "r != -1.0");
+ }
+
+ /* LL_I2L -- Convert 32bit signed to 64bit signed */
+ LL_I2L( result, one );
+ if ( LL_CMP(result, !=, bigOne )) {
+ SetFailed( "LL_I2L", "r != 1");
+ }
+
+ LL_I2L( result, minusOne );
+ if ( LL_CMP(result, !=, bigMinusOne )) {
+ SetFailed( "LL_I2L", "r != -1");
+ }
+
+ /* LL_UI2L -- Convert 32bit unsigned to 64bit unsigned */
+ LL_UI2L( resultU, (PRUint32) one );
+ if ( LL_CMP(resultU, !=, bigOne )) {
+ SetFailed( "LL_UI2L", "r != 1");
+ }
+
+ /* [lth.] This did not behave as expected, but it is correct
+ */
+ LL_UI2L( resultU, (PRUint32) minusOne );
+ if ( LL_CMP(resultU, !=, bigZeroFox )) {
+ ResultFailed( "LL_UI2L", "r != -1", bigZeroFox, resultU);
+ }
+
+ /* LL_F2L -- Convert 32bit float to 64bit signed */
+ LL_F2L( result, 1.0 );
+ if ( LL_CMP(result, !=, bigOne )) {
+ SetFailed( "LL_F2L", "r != 1");
+ }
+
+ LL_F2L( result, -1.0 );
+ if ( LL_CMP(result, !=, bigMinusOne )) {
+ SetFailed( "LL_F2L", "r != -1");
+ }
+
+ /* LL_D2L -- Convert 64bit Float to 64bit signed */
+ LL_D2L( result, 1.0L );
+ if ( LL_CMP(result, !=, bigOne )) {
+ SetFailed( "LL_D2L", "r != 1");
+ }
+
+ LL_D2L( result, -1.0L );
+ if ( LL_CMP(result, !=, bigMinusOne )) {
+ SetFailed( "LL_D2L", "r != -1");
+ }
+
+ return;
+}
+
+static void ShiftCompileOnly()
+{
+ /*
+ ** This function is only compiled, never called.
+ ** The real test is to see if it compiles w/o
+ ** warnings. This is no small feat, by the way.
+ */
+ PRInt64 ia, ib;
+ PRUint64 ua, ub;
+ LL_SHR(ia, ib, 32);
+ LL_SHL(ia, ib, 32);
+
+ LL_USHR(ua, ub, 32);
+ LL_ISHL(ia, 49, 32);
+
+} /* ShiftCompileOnly */
+
+
+/*
+** TestShift() -- Test Shifting Operations
+**
+*/
+static void
+TestShift( void )
+{
+ static const PRInt64 largeTwoZero = LL_INIT( 0x00000002, 0x00000000 );
+ PRInt64 result;
+ PRUint64 resultU;
+
+ ReportProgress("Testing Shifting Operations\n");
+
+ /* LL_SHL -- Shift left algebraic */
+ LL_SHL( result, bigOne, one );
+ if ( LL_CMP( result, !=, bigTwo )) {
+ ResultFailed( "LL_SHL", "r != 2", bigOne, result );
+ }
+
+ LL_SHL( result, bigTwo, thirtyTwo );
+ if ( LL_CMP( result, !=, largeTwoZero )) {
+ ResultFailed( "LL_SHL", "r != twoZero", largeTwoZero, result);
+ }
+
+ /* LL_SHR -- Shift right algebraic */
+ LL_SHR( result, bigFoxZero, thirtyTwo );
+ if ( LL_CMP( result, !=, bigMinusOne )) {
+ ResultFailed( "LL_SHR", "r != -1", bigMinusOne, result);
+ }
+
+ LL_SHR( result, bigTwo, one );
+ if ( LL_CMP( result, !=, bigOne )) {
+ ResultFailed( "LL_SHR", "r != 1", bigOne, result);
+ }
+
+ LL_SHR( result, bigFoxFox, thirtyTwo );
+ if ( LL_CMP( result, !=, bigMinusOne )) {
+ ResultFailed( "LL_SHR", "r != -1 (was ff,ff)", bigMinusOne, result);
+ }
+
+ /* LL_USHR -- Logical shift right */
+ LL_USHR( resultU, bigZeroFox, thirtyTwo );
+ if ( LL_UCMP( resultU, !=, bigZero )) {
+ ResultFailed( "LL_USHR", "r != 0 ", bigZero, result);
+ }
+
+ LL_USHR( resultU, bigFoxFox, thirtyTwo );
+ if ( LL_UCMP( resultU, !=, bigZeroFox )) {
+ ResultFailed( "LL_USHR", "r != 0 ", bigZeroFox, result);
+ }
+
+ /* LL_ISHL -- Shift a 32bit integer into a 64bit result */
+ LL_ISHL( resultU, minusOne, thirtyTwo );
+ if ( LL_UCMP( resultU, !=, bigFoxZero )) {
+ ResultFailed( "LL_ISHL", "r != ff,00 ", bigFoxZero, result);
+ }
+
+ LL_ISHL( resultU, one, sixtyThree );
+ if ( LL_UCMP( resultU, !=, bigEightZero )) {
+ ResultFailed( "LL_ISHL", "r != 80,00 ", bigEightZero, result);
+ }
+
+ LL_ISHL( resultU, one, sixteen );
+ if ( LL_UCMP( resultU, !=, big64K )) {
+ ResultFailed( "LL_ISHL", "r != 64K ", big64K, resultU);
+ }
+
+ return;
+}
+
+
+/*
+** TestArithmetic() -- Test arithmetic operations.
+**
+*/
+static void
+TestArithmetic( void )
+{
+ PRInt64 largeVal = LL_INIT( 0x00000001, 0xffffffff );
+ PRInt64 largeValPlusOne = LL_INIT( 0x00000002, 0x00000000 );
+ PRInt64 largeValTimesTwo = LL_INIT( 0x00000003, 0xfffffffe );
+ PRInt64 largeMultCand = LL_INIT( 0x00000000, 0x7fffffff );
+ PRInt64 largeMinusMultCand = LL_INIT( 0xffffffff, 0x10000001 );
+ PRInt64 largeMultCandx64K = LL_INIT( 0x00007fff, 0xffff0000 );
+ PRInt64 largeNumSHL5 = LL_INIT( 0x0000001f, 0xffffffe0 );
+ PRInt64 result, result2;
+
+ /* Addition */
+ LL_ADD( result, bigOne, bigOne );
+ if ( LL_CMP( result, !=, bigTwo )) {
+ ResultFailed( "LL_ADD", "r != 1 + 1", bigTwo, result);
+ }
+
+ LL_ADD( result, bigMinusOne, bigOne );
+ if ( LL_CMP( result, !=, bigZero )) {
+ ResultFailed( "LL_ADD", "r != -1 + 1", bigOne, result);
+ }
+
+ LL_ADD( result, largeVal, bigOne );
+ if ( LL_CMP( result, !=, largeValPlusOne )) {
+ ResultFailed( "LL_ADD", "lVP1 != lV + 1", largeValPlusOne, result);
+ }
+
+ /* Subtraction */
+ LL_SUB( result, bigOne, bigOne );
+ if ( LL_CMP( result, !=, bigZero )) {
+ ResultFailed( "LL_SUB", "r != 1 - 1", bigZero, result);
+ }
+
+ LL_SUB( result, bigTwo, bigOne );
+ if ( LL_CMP( result, !=, bigOne )) {
+ ResultFailed( "LL_SUB", "r != 2 - 1", bigOne, result);
+ }
+
+ LL_SUB( result, largeValPlusOne, bigOne );
+ if ( LL_CMP( result, !=, largeVal )) {
+ ResultFailed( "LL_SUB", "r != lVP1 - 1", largeVal, result);
+ }
+
+
+ /* Multiply */
+ LL_MUL( result, largeVal, bigTwo );
+ if ( LL_CMP( result, !=, largeValTimesTwo )) {
+ ResultFailed( "LL_MUL", "r != lV*2", largeValTimesTwo, result);
+ }
+
+ LL_MUL( result, largeMultCand, big64K );
+ if ( LL_CMP( result, !=, largeMultCandx64K )) {
+ ResultFailed( "LL_MUL", "r != lV*64K", largeMultCandx64K, result);
+ }
+
+ LL_NEG( result2, largeMultCand );
+ LL_MUL( result, largeMultCand, bigMinusOne );
+ if ( LL_CMP( result, !=, result2 )) {
+ ResultFailed( "LL_MUL", "r != -lMC", result2, result);
+ }
+
+ LL_SHL( result2, bigZeroFox, 5);
+ LL_MUL( result, bigZeroFox, bigThirtyTwo );
+ if ( LL_CMP( result, !=, largeNumSHL5 )) {
+ ResultFailed( "LL_MUL", "r != 0f<<5", largeNumSHL5, result );
+ }
+
+
+
+ /* LL_DIV() Division */
+ LL_DIV( result, bigOne, bigOne);
+ if ( LL_CMP( result, !=, bigOne )) {
+ ResultFailed( "LL_DIV", "1 != 1", bigOne, result);
+ }
+
+ LL_DIV( result, bigNumber, bigOne );
+ if ( LL_CMP( result, !=, bigNumber )) {
+ ResultFailed( "LL_DIV", "r != n / 1", bigNumber, result);
+ }
+
+ LL_DIV( result, bigNumber, bigMinusOne );
+ if ( LL_CMP( result, !=, bigMinusNumber )) {
+ ResultFailed( "LL_DIV", "r != n / -1", bigMinusNumber, result);
+ }
+
+ LL_DIV( result, bigMinusNumber, bigMinusOne );
+ if ( LL_CMP( result, !=, bigNumber )) {
+ ResultFailed( "LL_DIV", "r != -n / -1", bigNumber, result);
+ }
+
+ LL_SHL( result2, bigZeroFox, 5 );
+ LL_DIV( result, result2, bigOne );
+ if ( LL_CMP( result, !=, result2 )) {
+ ResultFailed( "LL_DIV", "0f<<5 != 0f<<5", result2, result);
+ }
+
+ LL_SHL( result2, bigZeroFox, 5 );
+ LL_NEG( result2, result2 );
+ LL_DIV( result, result2, bigOne );
+ if ( LL_CMP( result, !=, result2 )) {
+ ResultFailed( "LL_DIV", "-0f<<5 != -0f<<5", result2, result);
+ }
+
+ LL_SHL( result2, bigZeroFox, 17 );
+ LL_DIV( result, result2, bigMinusOne );
+ LL_NEG( result2, result2 );
+ if ( LL_CMP( result, !=, result2 )) {
+ ResultFailed( "LL_DIV", "-0f<<17 != -0f<<17", result2, result);
+ }
+
+
+ /* LL_MOD() Modulo Division */
+ LL_ADD( result2, bigThirtyTwo, bigOne );
+ LL_MOD( result, result2, bigSixTeen );
+ if ( LL_CMP( result, !=, bigOne )) {
+ ResultFailed( "LL_MOD", "r != 1", bigSixTeen, result);
+ }
+
+
+ LL_MUL( result2, bigZeroFox, bigThirtyTwo );
+ LL_ADD( result2, result2, bigSixTeen);
+ LL_MOD( result, result2, bigThirtyTwo );
+ if ( LL_CMP( result, !=, bigSixTeen )) {
+ ResultFailed( "LL_MOD", "r != 16", bigSixTeen, result);
+ }
+
+ /* LL_UDIVMOD */
+ LL_DIV( result, bigOne, bigOne);
+ if ( LL_CMP( result, !=, bigOne )) {
+ ResultFailed( "LL_DIV", "r != 16", bigSixTeen, result);
+ }
+
+
+ return;
+}
+
+static void TestWellknowns(void)
+{
+ PRInt64 max = LL_MAXINT, min = LL_MININT, zero = LL_ZERO;
+ PRInt64 mmax = LL_MaxInt(), mmin = LL_MinInt(), mzero = LL_Zero();
+ if (LL_NE(max, mmax)) {
+ ResultFailed( "max, mmax", "max != mmax", max, mmax);
+ }
+ if (LL_NE(min, mmin)) {
+ ResultFailed( "min, mmin", "min != mmin", max, mmin);
+ }
+ if (LL_NE(zero, mzero)) {
+ ResultFailed( "zero, mzero", "zero != mzero", zero, mzero);
+ }
+} /* TestWellknowns */
+
+/*
+** Initialize() -- Initialize the test case
+**
+** Parse command line options
+**
+*/
+static PRIntn
+Initialize( PRIntn argc, char **argv )
+{
+ PLOptState *opt = PL_CreateOptState(argc, argv, "dvh");
+ PLOptStatus os;
+
+ /*
+ ** Parse command line options
+ */
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 'd': /* set debug mode */
+ debugMode = PR_TRUE;
+ break;
+
+ case 'v': /* set verbose mode */
+ verboseMode = PR_TRUE;
+ debugMode = PR_TRUE;
+ break;
+
+ case 'h': /* user wants some guidance */
+ default:
+ PR_fprintf(output, "You get help.\n");
+ return(1);
+ }
+ }
+ PL_DestroyOptState(opt);
+ return(0);
+}
+
+int main(int argc, char **argv)
+{
+ PR_STDIO_INIT();
+ output = PR_GetSpecialFD(PR_StandardError);
+
+ if ( Initialize( argc, argv )) {
+ return(1);
+ }
+
+ TestAssignment();
+ TestComparisons();
+ TestLogicalOperations();
+ TestConversion();
+ TestShift();
+ TestArithmetic();
+ TestWellknowns();
+
+ /*
+ ** That's all folks!
+ */
+ if ( failedAlready )
+ {
+ PR_fprintf(output, "FAIL\n"); \
+ }
+ else
+ {
+ PR_fprintf(output, "PASS\n"); \
+ }
+ return failedAlready;
+} /* end main() */
diff --git a/nsprpub/pr/tests/lock.c b/nsprpub/pr/tests/lock.c
new file mode 100644
index 0000000000..83a4f41801
--- /dev/null
+++ b/nsprpub/pr/tests/lock.c
@@ -0,0 +1,548 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+** File: lock.c
+** Purpose: test basic locking functions
+**
+** Modification History:
+** 14-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
+** The debug mode will print all of the printfs associated with this test.
+** The regress mode will be the default mode. Since the regress tool limits
+** the output to a one line status:PASS or FAIL,all of the printf statements
+** have been handled with an if (debug_mode) statement.
+** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to
+** recognize the return code from tha main program.
+**
+** 11-Aug-97 LarryH. Win16 port of NSPR.
+** - Added "PASS", "FAIL" messages on completion.
+** - Change stack variables to static scope variables
+** because of shadow-stack use by Win16
+** - Added PR_CALLBACK attribute to functions called by NSPR
+** - Added command line arguments:
+** - l <num> to control the number of loops
+** - c <num> to control the number of CPUs.
+** (was positional argv).
+**
+**
+***********************************************************************/
+
+/***********************************************************************
+** Includes
+***********************************************************************/
+/* Used to get the command line option */
+#include "plgetopt.h"
+
+#include "prio.h"
+#include "prcmon.h"
+#include "prinit.h"
+#include "prinrval.h"
+#include "prprf.h"
+#include "prlock.h"
+#include "prlog.h"
+#include "prmon.h"
+#include "prmem.h"
+#include "prthread.h"
+#include "prtypes.h"
+
+#include "plstr.h"
+
+#include <stdlib.h>
+
+#if defined(XP_UNIX)
+#include <string.h>
+#endif
+
+static PRIntn failed_already=0;
+static PRFileDesc *std_err = NULL;
+static PRBool verbosity = PR_FALSE;
+static PRBool debug_mode = PR_FALSE;
+
+const static PRIntervalTime contention_interval = 50;
+
+typedef struct LockContentious_s {
+ PRLock *ml;
+ PRInt32 loops;
+ PRUint32 contender;
+ PRUint32 contentious;
+ PRIntervalTime overhead;
+ PRIntervalTime interval;
+} LockContentious_t;
+
+typedef struct MonitorContentious_s {
+ PRMonitor *ml;
+ PRInt32 loops;
+ PRUint32 contender;
+ PRUint32 contentious;
+ PRIntervalTime overhead;
+ PRIntervalTime interval;
+} MonitorContentious_t;
+
+
+static PRIntervalTime Sleeper(PRUint32 loops)
+{
+ PRIntervalTime predicted = 0;
+ while (loops-- > 0)
+ {
+ predicted += contention_interval;
+ (void)PR_Sleep(contention_interval);
+ }
+ return predicted;
+} /* Sleeper */
+
+/*
+** BASIC LOCKS
+*/
+static PRIntervalTime MakeLock(PRUint32 loops)
+{
+ PRLock *ml = NULL;
+ while (loops-- > 0)
+ {
+ ml = PR_NewLock();
+ PR_DestroyLock(ml);
+ ml = NULL;
+ }
+ return 0;
+} /* MakeLock */
+
+static PRIntervalTime NonContentiousLock(PRUint32 loops)
+{
+ PRLock *ml = NULL;
+ ml = PR_NewLock();
+ while (loops-- > 0)
+ {
+ PR_Lock(ml);
+ PR_ASSERT_CURRENT_THREAD_OWNS_LOCK(ml);
+ PR_Unlock(ml);
+ }
+ PR_DestroyLock(ml);
+ return 0;
+} /* NonContentiousLock */
+
+static void PR_CALLBACK LockContender(void *arg)
+{
+ LockContentious_t *contention = (LockContentious_t*)arg;
+ while (contention->loops-- > 0)
+ {
+ PR_Lock(contention->ml);
+ PR_ASSERT_CURRENT_THREAD_OWNS_LOCK(contention->ml);
+ contention->contender+= 1;
+ contention->overhead += contention->interval;
+ PR_Sleep(contention->interval);
+ PR_ASSERT_CURRENT_THREAD_OWNS_LOCK(contention->ml);
+ PR_Unlock(contention->ml);
+ }
+} /* LockContender */
+
+static PRIntervalTime ContentiousLock(PRUint32 loops)
+{
+ PRStatus status;
+ PRThread *thread = NULL;
+ LockContentious_t * contention;
+ PRIntervalTime rv, overhead, timein = PR_IntervalNow();
+
+ contention = PR_NEWZAP(LockContentious_t);
+ contention->loops = loops;
+ contention->overhead = 0;
+ contention->ml = PR_NewLock();
+ contention->interval = contention_interval;
+ thread = PR_CreateThread(
+ PR_USER_THREAD, LockContender, contention,
+ PR_PRIORITY_LOW, PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0);
+ PR_ASSERT(thread != NULL);
+
+ overhead = PR_IntervalNow() - timein;
+
+ while (contention->loops-- > 0)
+ {
+ PR_Lock(contention->ml);
+ PR_ASSERT_CURRENT_THREAD_OWNS_LOCK(contention->ml);
+ contention->contentious+= 1;
+ contention->overhead += contention->interval;
+ PR_Sleep(contention->interval);
+ PR_ASSERT_CURRENT_THREAD_OWNS_LOCK(contention->ml);
+ PR_Unlock(contention->ml);
+ }
+
+ timein = PR_IntervalNow();
+ status = PR_JoinThread(thread);
+ PR_DestroyLock(contention->ml);
+ overhead += (PR_IntervalNow() - timein);
+ rv = overhead + contention->overhead;
+ if (verbosity)
+ PR_fprintf(
+ std_err, "Access ratio: %u to %u\n",
+ contention->contentious, contention->contender);
+ PR_Free(contention);
+ return rv;
+} /* ContentiousLock */
+
+/*
+** MONITORS
+*/
+static PRIntervalTime MakeMonitor(PRUint32 loops)
+{
+ PRMonitor *ml = NULL;
+ while (loops-- > 0)
+ {
+ ml = PR_NewMonitor();
+ PR_DestroyMonitor(ml);
+ ml = NULL;
+ }
+ return 0;
+} /* MakeMonitor */
+
+static PRIntervalTime NonContentiousMonitor(PRUint32 loops)
+{
+ PRMonitor *ml = NULL;
+ ml = PR_NewMonitor();
+ while (loops-- > 0)
+ {
+ PR_EnterMonitor(ml);
+ PR_ASSERT_CURRENT_THREAD_IN_MONITOR(ml);
+ PR_ExitMonitor(ml);
+ }
+ PR_DestroyMonitor(ml);
+ return 0;
+} /* NonContentiousMonitor */
+
+static void PR_CALLBACK TryEntry(void *arg)
+{
+ PRMonitor *ml = (PRMonitor*)arg;
+ if (debug_mode) {
+ PR_fprintf(std_err, "Reentrant thread created\n");
+ }
+ PR_EnterMonitor(ml);
+ PR_ASSERT_CURRENT_THREAD_IN_MONITOR(ml);
+ if (debug_mode) {
+ PR_fprintf(std_err, "Reentrant thread acquired monitor\n");
+ }
+ PR_ExitMonitor(ml);
+ if (debug_mode) {
+ PR_fprintf(std_err, "Reentrant thread released monitor\n");
+ }
+} /* TryEntry */
+
+static PRIntervalTime ReentrantMonitor(PRUint32 loops)
+{
+ PRStatus status;
+ PRThread *thread;
+ PRMonitor *ml = PR_NewMonitor();
+ if (debug_mode) {
+ PR_fprintf(std_err, "\nMonitor created for reentrant test\n");
+ }
+
+ PR_EnterMonitor(ml);
+ PR_ASSERT_CURRENT_THREAD_IN_MONITOR(ml);
+ PR_EnterMonitor(ml);
+ PR_ASSERT_CURRENT_THREAD_IN_MONITOR(ml);
+ if (debug_mode) {
+ PR_fprintf(std_err, "Monitor acquired twice\n");
+ }
+
+ thread = PR_CreateThread(
+ PR_USER_THREAD, TryEntry, ml,
+ PR_PRIORITY_LOW, PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0);
+ PR_ASSERT(thread != NULL);
+ PR_Sleep(PR_SecondsToInterval(1));
+ PR_ASSERT_CURRENT_THREAD_IN_MONITOR(ml);
+
+ PR_ExitMonitor(ml);
+ PR_ASSERT_CURRENT_THREAD_IN_MONITOR(ml);
+ if (debug_mode) {
+ PR_fprintf(std_err, "Monitor released first time\n");
+ }
+
+ PR_ExitMonitor(ml);
+ if (debug_mode) {
+ PR_fprintf(std_err, "Monitor released second time\n");
+ }
+
+ status = PR_JoinThread(thread);
+ if (debug_mode) PR_fprintf(std_err,
+ "Reentrant thread joined %s\n",
+ (status == PR_SUCCESS) ? "successfully" : "in error");
+
+ PR_DestroyMonitor(ml);
+ return 0;
+} /* ReentrantMonitor */
+
+static void PR_CALLBACK MonitorContender(void *arg)
+{
+ MonitorContentious_t *contention = (MonitorContentious_t*)arg;
+ while (contention->loops-- > 0)
+ {
+ PR_EnterMonitor(contention->ml);
+ PR_ASSERT_CURRENT_THREAD_IN_MONITOR(contention->ml);
+ contention->contender+= 1;
+ contention->overhead += contention->interval;
+ PR_Sleep(contention->interval);
+ PR_ASSERT_CURRENT_THREAD_IN_MONITOR(contention->ml);
+ PR_ExitMonitor(contention->ml);
+ }
+} /* MonitorContender */
+
+static PRUint32 ContentiousMonitor(PRUint32 loops)
+{
+ PRStatus status;
+ PRThread *thread = NULL;
+ MonitorContentious_t * contention;
+ PRIntervalTime rv, overhead, timein = PR_IntervalNow();
+
+ contention = PR_NEWZAP(MonitorContentious_t);
+ contention->loops = loops;
+ contention->overhead = 0;
+ contention->ml = PR_NewMonitor();
+ contention->interval = contention_interval;
+ thread = PR_CreateThread(
+ PR_USER_THREAD, MonitorContender, contention,
+ PR_PRIORITY_LOW, PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0);
+ PR_ASSERT(thread != NULL);
+
+ overhead = PR_IntervalNow() - timein;
+
+ while (contention->loops-- > 0)
+ {
+ PR_EnterMonitor(contention->ml);
+ PR_ASSERT_CURRENT_THREAD_IN_MONITOR(contention->ml);
+ contention->contentious+= 1;
+ contention->overhead += contention->interval;
+ PR_Sleep(contention->interval);
+ PR_ASSERT_CURRENT_THREAD_IN_MONITOR(contention->ml);
+ PR_ExitMonitor(contention->ml);
+ }
+
+ timein = PR_IntervalNow();
+ status = PR_JoinThread(thread);
+ PR_DestroyMonitor(contention->ml);
+ overhead += (PR_IntervalNow() - timein);
+ rv = overhead + contention->overhead;
+ if (verbosity)
+ PR_fprintf(
+ std_err, "Access ratio: %u to %u\n",
+ contention->contentious, contention->contender);
+ PR_Free(contention);
+ return rv;
+} /* ContentiousMonitor */
+
+/*
+** CACHED MONITORS
+*/
+static PRIntervalTime NonContentiousCMonitor(PRUint32 loops)
+{
+ MonitorContentious_t contention;
+ while (loops-- > 0)
+ {
+ PR_CEnterMonitor(&contention);
+ PR_CExitMonitor(&contention);
+ }
+ return 0;
+} /* NonContentiousCMonitor */
+
+static void PR_CALLBACK Contender(void *arg)
+{
+ MonitorContentious_t *contention = (MonitorContentious_t*)arg;
+ while (contention->loops-- > 0)
+ {
+ PR_CEnterMonitor(contention);
+ contention->contender+= 1;
+ contention->overhead += contention->interval;
+ PR_Sleep(contention->interval);
+ PR_CExitMonitor(contention);
+ }
+} /* Contender */
+
+static PRIntervalTime ContentiousCMonitor(PRUint32 loops)
+{
+ PRStatus status;
+ PRThread *thread = NULL;
+ MonitorContentious_t * contention;
+ PRIntervalTime overhead, timein = PR_IntervalNow();
+
+ contention = PR_NEWZAP(MonitorContentious_t);
+ contention->ml = NULL;
+ contention->loops = loops;
+ contention->interval = contention_interval;
+ thread = PR_CreateThread(
+ PR_USER_THREAD, Contender, contention,
+ PR_PRIORITY_LOW, PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0);
+ PR_ASSERT(thread != NULL);
+
+ overhead = PR_IntervalNow() - timein;
+
+ while (contention->loops-- > 0)
+ {
+ PR_CEnterMonitor(contention);
+ contention->contentious+= 1;
+ contention->overhead += contention->interval;
+ PR_Sleep(contention->interval);
+ PR_CExitMonitor(contention);
+ }
+
+ timein = PR_IntervalNow();
+ status = PR_JoinThread(thread);
+ overhead += (PR_IntervalNow() - timein);
+ overhead += overhead + contention->overhead;
+ if (verbosity)
+ PR_fprintf(
+ std_err, "Access ratio: %u to %u\n",
+ contention->contentious, contention->contender);
+ PR_Free(contention);
+ return overhead;
+} /* ContentiousCMonitor */
+
+static PRIntervalTime Test(
+ const char* msg, PRUint32 (*test)(PRUint32 loops),
+ PRUint32 loops, PRIntervalTime overhead)
+{
+ /*
+ * overhead - overhead not measured by the test.
+ * duration - wall clock time it took to perform test.
+ * predicted - extra time test says should not be counted
+ *
+ * Time accountable to the test is duration - overhead - predicted
+ * All times are Intervals and accumulated for all iterations.
+ */
+ PRFloat64 elapsed;
+ PRIntervalTime accountable, duration;
+ PRUintn spaces = PL_strlen(msg);
+ PRIntervalTime timeout, timein = PR_IntervalNow();
+ PRIntervalTime predicted = test(loops);
+ timeout = PR_IntervalNow();
+ duration = timeout - timein;
+
+ if (debug_mode)
+ {
+ accountable = duration - predicted;
+ accountable -= overhead;
+ elapsed = (PRFloat64)PR_IntervalToMicroseconds(accountable);
+ PR_fprintf(PR_STDOUT, "%s:", msg);
+ while (spaces++ < 50) {
+ PR_fprintf(PR_STDOUT, " ");
+ }
+ if ((PRInt32)accountable < 0) {
+ PR_fprintf(PR_STDOUT, "*****.** usecs/iteration\n");
+ }
+ else {
+ PR_fprintf(PR_STDOUT, "%8.2f usecs/iteration\n", elapsed/loops);
+ }
+ }
+ return duration;
+} /* Test */
+
+int main(int argc, char **argv)
+{
+ PRBool rv = PR_TRUE;
+ PRIntervalTime duration;
+ PRUint32 cpu, cpus = 2, loops = 100;
+
+
+ PR_STDIO_INIT();
+ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
+ {
+ /* The command line argument: -d is used to determine if the test is being run
+ in debug mode. The regress tool requires only one line output:PASS or FAIL.
+ All of the printfs associated with this test has been handled with a if (debug_mode)
+ test.
+ Command line argument -l <num> sets the number of loops.
+ Command line argument -c <num> sets the number of cpus.
+ Usage: lock [-d] [-l <num>] [-c <num>]
+ */
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "dvl:c:");
+ 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 'v': /* debug mode */
+ verbosity = PR_TRUE;
+ break;
+ case 'l': /* number of loops */
+ loops = atoi(opt->value);
+ break;
+ case 'c': /* number of cpus */
+ cpus = atoi(opt->value);
+ break;
+ default:
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+ }
+
+ /* main test */
+ PR_SetConcurrency(8);
+
+ if (loops == 0) {
+ loops = 100;
+ }
+ if (debug_mode)
+ {
+ std_err = PR_STDERR;
+ PR_fprintf(std_err, "Lock: Using %d loops\n", loops);
+ }
+
+ if (cpus == 0) {
+ cpus = 2;
+ }
+ if (debug_mode) {
+ PR_fprintf(std_err, "Lock: Using %d cpu(s)\n", cpus);
+ }
+
+ (void)Sleeper(10); /* try filling in the caches */
+
+ for (cpu = 1; cpu <= cpus; ++cpu)
+ {
+ if (debug_mode) {
+ PR_fprintf(std_err, "\nLock: Using %d CPU(s)\n", cpu);
+ }
+ PR_SetConcurrency(cpu);
+
+ duration = Test("Overhead of PR_Sleep", Sleeper, loops, 0);
+ duration = 0;
+
+ (void)Test("Lock creation/deletion", MakeLock, loops, 0);
+ (void)Test("Lock non-contentious locking/unlocking", NonContentiousLock, loops, 0);
+ (void)Test("Lock contentious locking/unlocking", ContentiousLock, loops, duration);
+ (void)Test("Monitor creation/deletion", MakeMonitor, loops, 0);
+ (void)Test("Monitor non-contentious locking/unlocking", NonContentiousMonitor, loops, 0);
+ (void)Test("Monitor contentious locking/unlocking", ContentiousMonitor, loops, duration);
+
+ (void)Test("Cached monitor non-contentious locking/unlocking", NonContentiousCMonitor, loops, 0);
+ (void)Test("Cached monitor contentious locking/unlocking", ContentiousCMonitor, loops, duration);
+
+ (void)ReentrantMonitor(loops);
+ }
+
+ if (debug_mode)
+ PR_fprintf(
+ std_err, "%s: test %s\n", "Lock(mutex) test",
+ ((rv) ? "passed" : "failed"));
+ else {
+ if (!rv) {
+ failed_already=1;
+ }
+ }
+
+ if(failed_already)
+ {
+ PR_fprintf(PR_STDOUT, "FAIL\n");
+ return 1;
+ }
+ else
+ {
+ PR_fprintf(PR_STDOUT, "PASS\n");
+ return 0;
+ }
+
+} /* main */
+
+/* testlock.c */
diff --git a/nsprpub/pr/tests/lockfile.c b/nsprpub/pr/tests/lockfile.c
new file mode 100644
index 0000000000..883ef0d615
--- /dev/null
+++ b/nsprpub/pr/tests/lockfile.c
@@ -0,0 +1,255 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+** File: lockfile.c
+** Purpose: test basic locking functions
+** Just because this times stuff, don't think its a perforamnce
+** test!!!
+**
+** Modification History:
+** 19-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
+** The debug mode will print all of the printfs associated with this test.
+** The regress mode will be the default mode. Since the regress tool limits
+** the output to a one line status:PASS or FAIL,all of the printf statements
+** have been handled with an if (debug_mode) statement.
+** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to
+** recognize the return code from tha main program.
+***********************************************************************/
+/***********************************************************************
+** Includes
+***********************************************************************/
+/* Used to get the command line option */
+#include "plgetopt.h"
+
+#include "prcmon.h"
+#include "prerror.h"
+#include "prinit.h"
+#include "prinrval.h"
+#include "prlock.h"
+#include "prlog.h"
+#include "prmon.h"
+#include "prthread.h"
+#include "prtypes.h"
+
+#include "private/pprio.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+PRIntn failed_already=0;
+PRIntn debug_mode;
+
+const static PRIntervalTime contention_interval = 50;
+
+typedef struct LockContentious_s {
+ PRLock *ml;
+ PRInt32 loops;
+ PRIntervalTime overhead;
+ PRIntervalTime interval;
+} LockContentious_t;
+
+#define LOCKFILE "prlock.fil"
+
+
+
+static PRIntervalTime NonContentiousLock(PRInt32 loops)
+{
+ PRFileDesc *_lockfile;
+ while (loops-- > 0)
+ {
+ _lockfile = PR_Open(LOCKFILE, PR_CREATE_FILE|PR_RDWR, 0666);
+ if (!_lockfile) {
+ if (debug_mode) printf(
+ "could not create lockfile: %d [%d]\n",
+ PR_GetError(), PR_GetOSError());
+ return PR_INTERVAL_NO_TIMEOUT;
+ }
+ PR_LockFile(_lockfile);
+ PR_UnlockFile(_lockfile);
+ PR_Close(_lockfile);
+ }
+ return 0;
+} /* NonContentiousLock */
+
+static void PR_CALLBACK LockContender(void *arg)
+{
+ LockContentious_t *contention = (LockContentious_t*)arg;
+ PRFileDesc *_lockfile;
+ while (contention->loops-- > 0)
+ {
+ _lockfile = PR_Open(LOCKFILE, PR_CREATE_FILE|PR_RDWR, 0666);
+ if (!_lockfile) {
+ if (debug_mode) printf(
+ "could not create lockfile: %d [%d]\n",
+ PR_GetError(), PR_GetOSError());
+ break;
+ }
+ PR_LockFile(_lockfile);
+ PR_Sleep(contention->interval);
+ PR_UnlockFile(_lockfile);
+ PR_Close(_lockfile);
+ }
+
+} /* LockContender */
+
+/*
+** Win16 requires things passed to Threads not be on the stack
+*/
+static LockContentious_t contention;
+
+static PRIntervalTime ContentiousLock(PRInt32 loops)
+{
+ PRStatus status;
+ PRThread *thread = NULL;
+ PRIntervalTime overhead, timein = PR_IntervalNow();
+
+ contention.loops = loops;
+ contention.overhead = 0;
+ contention.ml = PR_NewLock();
+ contention.interval = contention_interval;
+ thread = PR_CreateThread(
+ PR_USER_THREAD, LockContender, &contention,
+ PR_PRIORITY_LOW, PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0);
+ PR_ASSERT(thread != NULL);
+
+ overhead = PR_IntervalNow() - timein;
+
+ while (contention.loops > 0)
+ {
+ PR_Lock(contention.ml);
+ contention.overhead += contention.interval;
+ PR_Sleep(contention.interval);
+ PR_Unlock(contention.ml);
+ }
+
+ timein = PR_IntervalNow();
+ status = PR_JoinThread(thread);
+ PR_DestroyLock(contention.ml);
+ overhead += (PR_IntervalNow() - timein);
+ return overhead + contention.overhead;
+} /* ContentiousLock */
+
+static PRIntervalTime Test(
+ const char* msg, PRIntervalTime (*test)(PRInt32 loops),
+ PRInt32 loops, PRIntervalTime overhead)
+{
+ /*
+ * overhead - overhead not measured by the test.
+ * duration - wall clock time it took to perform test.
+ * predicted - extra time test says should not be counted
+ *
+ * Time accountable to the test is duration - overhead - predicted
+ * All times are Intervals and accumulated for all iterations.
+ */
+ PRFloat64 elapsed;
+ PRIntervalTime accountable, duration;
+ PRUintn spaces = strlen(msg);
+ PRIntervalTime timeout, timein = PR_IntervalNow();
+ PRIntervalTime predicted = test(loops);
+ timeout = PR_IntervalNow();
+ duration = timeout - timein;
+ accountable = duration - predicted;
+ accountable -= overhead;
+ elapsed = (PRFloat64)PR_IntervalToMicroseconds(accountable);
+ if (debug_mode) {
+ printf("%s:", msg);
+ }
+ while (spaces++ < 50) if (debug_mode) {
+ printf(" ");
+ }
+ if ((PRInt32)accountable < 0) {
+ if (debug_mode) {
+ printf("*****.** usecs/iteration\n");
+ }
+ } else {
+ if (debug_mode) {
+ printf("%8.2f usecs/iteration\n", elapsed/loops);
+ }
+ }
+ return duration;
+} /* Test */
+
+int main(int argc, char **argv)
+{
+ PRIntervalTime duration;
+ PRUint32 cpu, cpus = 2;
+ PRInt32 loops = 100;
+
+
+ /* The command line argument: -d is used to determine if the test is being run
+ in debug mode. The regress tool requires only one line output:PASS or FAIL.
+ All of the printfs associated with this test has been handled with a if (debug_mode)
+ test.
+ Usage: test_name -d
+ */
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "d:");
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 'd': /* debug mode */
+ debug_mode = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ /* main test */
+
+ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
+ PR_STDIO_INIT();
+
+ if (argc > 1) {
+ loops = atoi(argv[1]);
+ }
+ if (loops == 0) {
+ loops = 100;
+ }
+ if (debug_mode) {
+ printf("Lock: Using %d loops\n", loops);
+ }
+
+ cpus = (argc < 3) ? 2 : atoi(argv[2]);
+ if (cpus == 0) {
+ cpus = 2;
+ }
+ if (debug_mode) {
+ printf("Lock: Using %d cpu(s)\n", cpus);
+ }
+
+
+ for (cpu = 1; cpu <= cpus; ++cpu)
+ {
+ if (debug_mode) {
+ printf("\nLockFile: Using %d CPU(s)\n", cpu);
+ }
+ PR_SetConcurrency(cpu);
+
+ duration = Test("LockFile non-contentious locking/unlocking", NonContentiousLock, loops, 0);
+ (void)Test("LockFile contentious locking/unlocking", ContentiousLock, loops, duration);
+ }
+
+ PR_Delete(LOCKFILE); /* try to get rid of evidence */
+
+ if (debug_mode) {
+ printf("%s: test %s\n", "Lock(mutex) test", ((failed_already) ? "failed" : "passed"));
+ }
+ if(failed_already) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+} /* main */
+
+/* testlock.c */
diff --git a/nsprpub/pr/tests/logfile.c b/nsprpub/pr/tests/logfile.c
new file mode 100644
index 0000000000..d6997be1fe
--- /dev/null
+++ b/nsprpub/pr/tests/logfile.c
@@ -0,0 +1,38 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * A regression test for bug 491441. NSPR should not crash on startup in
+ * PR_SetLogFile when the NSPR_LOG_MODULES and NSPR_LOG_FILE environment
+ * variables are set.
+ *
+ * This test could be extended to be a full-blown test for NSPR_LOG_FILE.
+ */
+
+#include "prinit.h"
+#include "prlog.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+int main()
+{
+ PRLogModuleInfo *test_lm;
+
+ if (putenv("NSPR_LOG_MODULES=all:5") != 0) {
+ fprintf(stderr, "putenv failed\n");
+ exit(1);
+ }
+ if (putenv("NSPR_LOG_FILE=logfile.log") != 0) {
+ fprintf(stderr, "putenv failed\n");
+ exit(1);
+ }
+
+ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
+ test_lm = PR_NewLogModule("test");
+ PR_LOG(test_lm, PR_LOG_MIN, ("logfile: test log message"));
+ PR_Cleanup();
+ return 0;
+}
diff --git a/nsprpub/pr/tests/logger.c b/nsprpub/pr/tests/logger.c
new file mode 100644
index 0000000000..ee28d41d7c
--- /dev/null
+++ b/nsprpub/pr/tests/logger.c
@@ -0,0 +1,127 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * File: logger.c
+ * Description: test program for logging's basic functions
+ */
+
+#include "prinit.h"
+#include "prlog.h"
+#include "prlock.h"
+#include "prcvar.h"
+#include "prthread.h"
+#include "prinrval.h"
+
+#include <stdio.h>
+
+/* lth. re-define PR_LOG() */
+#if 0
+#undef PR_LOG_TEST
+#undef PR_LOG
+#define PR_LOG_TEST(_module,_level) ((_module)->level <= (_level))
+#define PR_LOG(_module,_level,_args) \
+ { \
+ if (PR_LOG_TEST(_module,_level)) \
+ PR_LogPrint _args ; \
+ }
+#endif
+
+
+static void Error(const char* msg)
+{
+ printf("\t%s\n", msg);
+} /* Error */
+
+static void PR_CALLBACK forked(void *arg)
+{
+ PRIntn i;
+ PRLock *ml;
+ PRCondVar *cv;
+
+ PR_LogPrint("%s logging creating mutex\n", (const char*)arg);
+ ml = PR_NewLock();
+ PR_LogPrint("%s logging creating condition variable\n", (const char*)arg);
+ cv = PR_NewCondVar(ml);
+
+ PR_LogPrint("%s waiting on condition timeout 10 times\n", (const char*)arg);
+ for (i = 0; i < 10; ++i)
+ {
+ PR_Lock(ml);
+ PR_WaitCondVar(cv, PR_SecondsToInterval(1));
+ PR_Unlock(ml);
+ }
+
+ PR_LogPrint("%s logging destroying condition variable\n", (const char*)arg);
+ PR_DestroyCondVar(cv);
+ PR_LogPrint("%s logging destroying mutex\n", (const char*)arg);
+ PR_DestroyLock(ml);
+ PR_LogPrint("%s forked thread exiting\n", (const char*)arg);
+}
+
+static void UserLogStuff( void )
+{
+ PRLogModuleInfo *myLM;
+ PRIntn i;
+
+ myLM = PR_NewLogModule( "userStuff" );
+ if (! myLM )
+ {
+ printf("UserLogStuff(): can't create new log module\n" );
+ return;
+ }
+
+ PR_LOG( myLM, PR_LOG_NOTICE, ("Log a Notice %d\n", 1 ));
+
+ for (i = 0; i < 10 ; i++ )
+ {
+ PR_LOG( myLM, PR_LOG_DEBUG, ("Log Debug number: %d\n", i));
+ PR_Sleep( 300 );
+ }
+
+} /* end UserLogStuff() */
+
+int main(int argc, char **argv)
+{
+ PRThread *thread;
+
+ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
+ PR_STDIO_INIT();
+
+ if (argc > 1)
+ {
+ if (!PR_SetLogFile(argv[1]))
+ {
+ Error("Access: Cannot create log file");
+ goto exit;
+ }
+ }
+
+ /* Start logging something here */
+ PR_LogPrint("%s logging into %s\n", argv[0], argv[1]);
+
+ PR_LogPrint("%s creating new thread\n", argv[0]);
+
+ /*
+ ** Now change buffering.
+ */
+ PR_SetLogBuffering( 65500 );
+ thread = PR_CreateThread(
+ PR_USER_THREAD, forked, (void*)argv[0], PR_PRIORITY_NORMAL,
+ PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0);
+ PR_LogPrint("%s joining thread\n", argv[0]);
+
+ UserLogStuff();
+
+ PR_JoinThread(thread);
+
+ PR_LogFlush();
+ return 0;
+
+exit:
+ return -1;
+}
+
+/* logger.c */
diff --git a/nsprpub/pr/tests/makedir.c b/nsprpub/pr/tests/makedir.c
new file mode 100644
index 0000000000..21b42c5a6f
--- /dev/null
+++ b/nsprpub/pr/tests/makedir.c
@@ -0,0 +1,67 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * This test calls PR_MakeDir to create a bunch of directories
+ * with various mode bits.
+ */
+
+#include "prio.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc, char **argv)
+{
+ if (PR_MakeDir("tdir0400", 0400) == PR_FAILURE) {
+ fprintf(stderr, "PR_MakeDir failed\n");
+ exit(1);
+ }
+ if (PR_MakeDir("tdir0200", 0200) == PR_FAILURE) {
+ fprintf(stderr, "PR_MakeDir failed\n");
+ exit(1);
+ }
+ if (PR_MakeDir("tdir0100", 0100) == PR_FAILURE) {
+ fprintf(stderr, "PR_MakeDir failed\n");
+ exit(1);
+ }
+ if (PR_MakeDir("tdir0500", 0500) == PR_FAILURE) {
+ fprintf(stderr, "PR_MakeDir failed\n");
+ exit(1);
+ }
+ if (PR_MakeDir("tdir0600", 0600) == PR_FAILURE) {
+ fprintf(stderr, "PR_MakeDir failed\n");
+ exit(1);
+ }
+ if (PR_MakeDir("tdir0300", 0300) == PR_FAILURE) {
+ fprintf(stderr, "PR_MakeDir failed\n");
+ exit(1);
+ }
+ if (PR_MakeDir("tdir0700", 0700) == PR_FAILURE) {
+ fprintf(stderr, "PR_MakeDir failed\n");
+ exit(1);
+ }
+ if (PR_MakeDir("tdir0640", 0640) == PR_FAILURE) {
+ fprintf(stderr, "PR_MakeDir failed\n");
+ exit(1);
+ }
+ if (PR_MakeDir("tdir0660", 0660) == PR_FAILURE) {
+ fprintf(stderr, "PR_MakeDir failed\n");
+ exit(1);
+ }
+ if (PR_MakeDir("tdir0644", 0644) == PR_FAILURE) {
+ fprintf(stderr, "PR_MakeDir failed\n");
+ exit(1);
+ }
+ if (PR_MakeDir("tdir0664", 0664) == PR_FAILURE) {
+ fprintf(stderr, "PR_MakeDir failed\n");
+ exit(1);
+ }
+ if (PR_MakeDir("tdir0666", 0666) == PR_FAILURE) {
+ fprintf(stderr, "PR_MakeDir failed\n");
+ exit(1);
+ }
+ return 0;
+}
diff --git a/nsprpub/pr/tests/many_cv.c b/nsprpub/pr/tests/many_cv.c
new file mode 100644
index 0000000000..8444c99576
--- /dev/null
+++ b/nsprpub/pr/tests/many_cv.c
@@ -0,0 +1,124 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "prinit.h"
+#include "prprf.h"
+#include "prthread.h"
+#include "prcvar.h"
+#include "prlock.h"
+#include "prlog.h"
+#include "prmem.h"
+
+#include "primpl.h"
+
+#include "plgetopt.h"
+
+#include <stdlib.h>
+
+static PRInt32 RandomNum(void)
+{
+ PRInt32 ran = rand() >> 16;
+ return ran;
+} /* RandomNum */
+
+static void Help(void)
+{
+ PRFileDesc *err = PR_GetSpecialFD(PR_StandardError);
+ PR_fprintf(err, "many_cv usage: [-c n] [-l n] [-h]\n");
+ PR_fprintf(err, "\t-c n Number of conditions per lock (default: 10)\n");
+ PR_fprintf(err, "\t-l n Number of times to loop the test (default: 1)\n");
+ PR_fprintf(err, "\t-h This message and nothing else\n");
+} /* Help */
+
+static PRIntn PR_CALLBACK RealMain( PRIntn argc, char **argv )
+{
+ PLOptStatus os;
+ PRIntn index, nl;
+ PRLock *ml = NULL;
+ PRCondVar **cv = NULL;
+ PRBool stats = PR_FALSE;
+ PRIntn nc, loops = 1, cvs = 10;
+ PRFileDesc *err = PR_GetSpecialFD(PR_StandardError);
+ PLOptState *opt = PL_CreateOptState(argc, argv, "hsc:l:");
+
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 's': /* number of CVs to association with lock */
+ stats = PR_TRUE;
+ break;
+ case 'c': /* number of CVs to association with lock */
+ cvs = atoi(opt->value);
+ break;
+ case 'l': /* number of times to run the tests */
+ loops = atoi(opt->value);
+ break;
+ case 'h': /* user wants some guidance */
+ default:
+ Help(); /* so give him an earful */
+ return 2; /* but not a lot else */
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ PR_fprintf(err, "Settings\n");
+ PR_fprintf(err, "\tConditions / lock: %d\n", cvs);
+ PR_fprintf(err, "\tLoops to run test: %d\n", loops);
+
+ ml = PR_NewLock();
+ PR_ASSERT(NULL != ml);
+
+ cv = (PRCondVar**)PR_CALLOC(sizeof(PRCondVar*) * cvs);
+ PR_ASSERT(NULL != cv);
+
+ for (index = 0; index < cvs; ++index)
+ {
+ cv[index] = PR_NewCondVar(ml);
+ PR_ASSERT(NULL != cv[index]);
+ }
+
+ for (index = 0; index < loops; ++index)
+ {
+ PR_Lock(ml);
+ for (nl = 0; nl < cvs; ++nl)
+ {
+ PRInt32 ran = RandomNum() % 8;
+ if (0 == ran) {
+ PR_NotifyAllCondVar(cv[nl]);
+ }
+ else for (nc = 0; nc < ran; ++nc) {
+ PR_NotifyCondVar(cv[nl]);
+ }
+ }
+ PR_Unlock(ml);
+ }
+
+ for (index = 0; index < cvs; ++index) {
+ PR_DestroyCondVar(cv[index]);
+ }
+
+ PR_DELETE(cv);
+
+ PR_DestroyLock(ml);
+
+ printf("PASS\n");
+
+ PT_FPrintStats(err, "\nPThread Statistics\n");
+ return 0;
+}
+
+
+int main(int argc, char **argv)
+{
+ PRIntn rv;
+
+ PR_STDIO_INIT();
+ rv = PR_Initialize(RealMain, argc, argv, 0);
+ return rv;
+} /* main */
diff --git a/nsprpub/pr/tests/mbcs.c b/nsprpub/pr/tests/mbcs.c
new file mode 100644
index 0000000000..1a0d08f840
--- /dev/null
+++ b/nsprpub/pr/tests/mbcs.c
@@ -0,0 +1,159 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+** File: mbcs.c
+**
+** Synopsis: mbcs {dirName}
+**
+** where dirName is the directory to be traversed. dirName is required.
+**
+** Description:
+** mbcs.c tests use of multi-byte characters, as would be passed to
+** NSPR funtions by internationalized applications.
+**
+** mbcs.c, when run on any single-byte platform, should run correctly.
+** In truth, running the mbcs test on a single-byte platform is
+** really meaningless. mbcs.c, nor any NSPR library or test is not
+** intended for use with any wide character set, including Unicode.
+** mbcs.c should not be included in runtests.ksh because it requires
+** extensive user intervention to set-up and run.
+**
+** mbcs.c should be run on a platform using some form of multi-byte
+** characters. The initial platform for this test is a Japanese
+** language Windows NT 4.0 machine. ... Thank you Noriko Hoshi.
+**
+** To run mbcs.c, the tester should create a directory tree containing
+** some files in the same directory from which the test is run; i.e.
+** the current working directory. The directory and files should be
+** named such that when represented in the local multi-byte character
+** set, one or more characters of the name is longer than a single
+** byte.
+**
+*/
+
+#include <plgetopt.h>
+#include <nspr.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+** Test harness infrastructure
+*/
+PRLogModuleInfo *lm;
+PRLogModuleLevel msgLevel = PR_LOG_NONE;
+PRIntn debug = 0;
+PRUint32 failed_already = 0;
+/* end Test harness infrastructure */
+
+char *dirName = NULL; /* directory name to traverse */
+
+/*
+** Traverse directory
+*/
+static void TraverseDirectory( unsigned char *dir )
+{
+ PRDir *cwd;
+ PRDirEntry *dirEntry;
+ PRFileInfo info;
+ PRStatus rc;
+ PRInt32 err;
+ PRFileDesc *fd;
+ char nextDir[256];
+ char file[256];
+
+ printf("Directory: %s\n", dir );
+ cwd = PR_OpenDir( dir );
+ if ( NULL == cwd ) {
+ printf("PR_OpenDir() failed on directory: %s, with error: %d, %d\n",
+ dir, PR_GetError(), PR_GetOSError());
+ exit(1);
+ }
+ while( NULL != (dirEntry = PR_ReadDir( cwd, PR_SKIP_BOTH | PR_SKIP_HIDDEN ))) {
+ sprintf( file, "%s/%s", dir, dirEntry->name );
+ rc = PR_GetFileInfo( file, &info );
+ if ( PR_FAILURE == rc ) {
+ printf("PR_GetFileInfo() failed on file: %s, with error: %d, %d\n",
+ dirEntry->name, PR_GetError(), PR_GetOSError());
+ exit(1);
+ }
+ if ( PR_FILE_FILE == info.type ) {
+ printf("File: %s \tsize: %ld\n", dirEntry->name, info.size );
+ fd = PR_Open( file, PR_RDONLY, 0 );
+ if ( NULL == fd ) {
+ printf("PR_Open() failed. Error: %ld, OSError: %ld\n",
+ PR_GetError(), PR_GetOSError());
+ }
+ rc = PR_Close( fd );
+ if ( PR_FAILURE == rc ) {
+ printf("PR_Close() failed. Error: %ld, OSError: %ld\n",
+ PR_GetError(), PR_GetOSError());
+ }
+ } else if ( PR_FILE_DIRECTORY == info.type ) {
+ sprintf( nextDir, "%s/%s", dir, dirEntry->name );
+ TraverseDirectory(nextDir);
+ } else {
+ printf("type is not interesting for file: %s\n", dirEntry->name );
+ /* keep going */
+ }
+ }
+ /* assume end-of-file, actually could be error */
+
+ rc = PR_CloseDir( cwd );
+ if ( PR_FAILURE == rc ) {
+ printf("PR_CloseDir() failed on directory: %s, with error: %d, %d\n",
+ dir, PR_GetError(), PR_GetOSError());
+ }
+
+} /* end TraverseDirectory() */
+
+int main(int argc, char **argv)
+{
+ { /* get command line options */
+ /*
+ ** Get command line options
+ */
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "dv");
+
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 'd': /* debug */
+ debug = 1;
+ msgLevel = PR_LOG_ERROR;
+ break;
+ case 'v': /* verbose mode */
+ msgLevel = PR_LOG_DEBUG;
+ break;
+ default:
+ dirName = strdup(opt->value);
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+ } /* end get command line options */
+
+ lm = PR_NewLogModule("Test"); /* Initialize logging */
+
+
+ if ( dirName == NULL ) {
+ printf("you gotta specify a directory as an operand!\n");
+ exit(1);
+ }
+
+ TraverseDirectory( dirName );
+
+ if (debug) {
+ printf("%s\n", (failed_already)? "FAIL" : "PASS");
+ }
+ return( (failed_already == PR_TRUE )? 1 : 0 );
+} /* main() */
+/* end template.c */
diff --git a/nsprpub/pr/tests/monref.c b/nsprpub/pr/tests/monref.c
new file mode 100644
index 0000000000..3e2ae637bf
--- /dev/null
+++ b/nsprpub/pr/tests/monref.c
@@ -0,0 +1,74 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * This test program demonstrates that PR_ExitMonitor needs to add a
+ * reference to the PRMonitor object before unlocking the internal
+ * mutex.
+ */
+
+#include "prlog.h"
+#include "prmon.h"
+#include "prthread.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+/* Protected by the PRMonitor 'mon' in the main function. */
+static PRBool done = PR_FALSE;
+
+static void ThreadFunc(void *arg)
+{
+ PRMonitor *mon = (PRMonitor *)arg;
+ PRStatus rv;
+
+ PR_EnterMonitor(mon);
+ done = PR_TRUE;
+ rv = PR_Notify(mon);
+ PR_ASSERT(rv == PR_SUCCESS);
+ rv = PR_ExitMonitor(mon);
+ PR_ASSERT(rv == PR_SUCCESS);
+}
+
+int main()
+{
+ PRMonitor *mon;
+ PRThread *thread;
+ PRStatus rv;
+
+ mon = PR_NewMonitor();
+ if (!mon) {
+ fprintf(stderr, "PR_NewMonitor failed\n");
+ exit(1);
+ }
+
+ thread = PR_CreateThread(PR_USER_THREAD, ThreadFunc, mon,
+ PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
+ PR_JOINABLE_THREAD, 0);
+ if (!thread) {
+ fprintf(stderr, "PR_CreateThread failed\n");
+ exit(1);
+ }
+
+ PR_EnterMonitor(mon);
+ while (!done) {
+ rv = PR_Wait(mon, PR_INTERVAL_NO_TIMEOUT);
+ PR_ASSERT(rv == PR_SUCCESS);
+ }
+ rv = PR_ExitMonitor(mon);
+ PR_ASSERT(rv == PR_SUCCESS);
+
+ /*
+ * Do you agree it should be safe to destroy 'mon' now?
+ * See bug 844784 comment 27.
+ */
+ PR_DestroyMonitor(mon);
+
+ rv = PR_JoinThread(thread);
+ PR_ASSERT(rv == PR_SUCCESS);
+
+ printf("PASS\n");
+ return 0;
+}
diff --git a/nsprpub/pr/tests/multiacc.c b/nsprpub/pr/tests/multiacc.c
new file mode 100644
index 0000000000..ff8452d3da
--- /dev/null
+++ b/nsprpub/pr/tests/multiacc.c
@@ -0,0 +1,220 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * File: multiacc.c
+ *
+ * Description:
+ * This test creates multiple threads that accept on the
+ * same listening socket.
+ */
+
+#include "nspr.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define NUM_SERVER_THREADS 10
+
+static int num_server_threads = NUM_SERVER_THREADS;
+static PRThreadScope thread_scope = PR_GLOBAL_THREAD;
+static PRBool exit_flag = PR_FALSE;
+
+static void ServerThreadFunc(void *arg)
+{
+ PRFileDesc *listenSock = (PRFileDesc *) arg;
+ PRFileDesc *acceptSock;
+ PRErrorCode err;
+ PRStatus status;
+
+ while (!exit_flag) {
+ acceptSock = PR_Accept(listenSock, NULL, PR_INTERVAL_NO_TIMEOUT);
+ if (NULL == acceptSock) {
+ err = PR_GetError();
+ if (PR_PENDING_INTERRUPT_ERROR == err) {
+ printf("server thread is interrupted\n");
+ fflush(stdout);
+ continue;
+ }
+ fprintf(stderr, "PR_Accept failed: %d\n", err);
+ exit(1);
+ }
+ status = PR_Close(acceptSock);
+ if (PR_FAILURE == status) {
+ fprintf(stderr, "PR_Close failed\n");
+ exit(1);
+ }
+ }
+}
+
+int main(int argc, char **argv)
+{
+ PRNetAddr serverAddr;
+ PRFileDesc *dummySock;
+ PRFileDesc *listenSock;
+ PRFileDesc *clientSock;
+ PRThread *dummyThread;
+ PRThread **serverThreads;
+ PRStatus status;
+ PRUint16 port;
+ int idx;
+ PRInt32 nbytes;
+ char buf[1024];
+
+ serverThreads = (PRThread **)
+ PR_Malloc(num_server_threads * sizeof(PRThread *));
+ if (NULL == serverThreads) {
+ fprintf(stderr, "PR_Malloc failed\n");
+ exit(1);
+ }
+
+ /*
+ * Create a dummy listening socket and have the first
+ * (dummy) thread listen on it. This is to ensure that
+ * the first thread becomes the I/O continuation thread
+ * in the pthreads implementation (see ptio.c) and remains
+ * so throughout the test, so that we never have to
+ * recycle the I/O continuation thread.
+ */
+ dummySock = PR_NewTCPSocket();
+ if (NULL == dummySock) {
+ fprintf(stderr, "PR_NewTCPSocket failed\n");
+ exit(1);
+ }
+ memset(&serverAddr, 0, sizeof(serverAddr));
+ status = PR_InitializeNetAddr(PR_IpAddrAny, 0, &serverAddr);
+ if (PR_FAILURE == status) {
+ fprintf(stderr, "PR_InitializeNetAddr failed\n");
+ exit(1);
+ }
+ status = PR_Bind(dummySock, &serverAddr);
+ if (PR_FAILURE == status) {
+ fprintf(stderr, "PR_Bind failed\n");
+ exit(1);
+ }
+ status = PR_Listen(dummySock, 5);
+ if (PR_FAILURE == status) {
+ fprintf(stderr, "PR_Listen failed\n");
+ exit(1);
+ }
+
+ listenSock = PR_NewTCPSocket();
+ if (NULL == listenSock) {
+ fprintf(stderr, "PR_NewTCPSocket failed\n");
+ exit(1);
+ }
+ memset(&serverAddr, 0, sizeof(serverAddr));
+ status = PR_InitializeNetAddr(PR_IpAddrAny, 0, &serverAddr);
+ if (PR_FAILURE == status) {
+ fprintf(stderr, "PR_InitializeNetAddr failed\n");
+ exit(1);
+ }
+ status = PR_Bind(listenSock, &serverAddr);
+ if (PR_FAILURE == status) {
+ fprintf(stderr, "PR_Bind failed\n");
+ exit(1);
+ }
+ status = PR_GetSockName(listenSock, &serverAddr);
+ if (PR_FAILURE == status) {
+ fprintf(stderr, "PR_GetSockName failed\n");
+ exit(1);
+ }
+ port = PR_ntohs(serverAddr.inet.port);
+ status = PR_Listen(listenSock, 5);
+ if (PR_FAILURE == status) {
+ fprintf(stderr, "PR_Listen failed\n");
+ exit(1);
+ }
+
+ printf("creating dummy thread\n");
+ fflush(stdout);
+ dummyThread = PR_CreateThread(PR_USER_THREAD,
+ ServerThreadFunc, dummySock, PR_PRIORITY_NORMAL,
+ thread_scope, PR_JOINABLE_THREAD, 0);
+ if (NULL == dummyThread) {
+ fprintf(stderr, "PR_CreateThread failed\n");
+ exit(1);
+ }
+ printf("sleeping one second before creating server threads\n");
+ fflush(stdout);
+ PR_Sleep(PR_SecondsToInterval(1));
+ for (idx = 0; idx < num_server_threads; idx++) {
+ serverThreads[idx] = PR_CreateThread(PR_USER_THREAD,
+ ServerThreadFunc, listenSock, PR_PRIORITY_NORMAL,
+ thread_scope, PR_JOINABLE_THREAD, 0);
+ if (NULL == serverThreads[idx]) {
+ fprintf(stderr, "PR_CreateThread failed\n");
+ exit(1);
+ }
+ }
+
+ memset(&serverAddr, 0, sizeof(serverAddr));
+ PR_InitializeNetAddr(PR_IpAddrLoopback, port, &serverAddr);
+ clientSock = PR_NewTCPSocket();
+ if (NULL == clientSock) {
+ fprintf(stderr, "PR_NewTCPSocket failed\n");
+ exit(1);
+ }
+ printf("sleeping one second before connecting\n");
+ fflush(stdout);
+ PR_Sleep(PR_SecondsToInterval(1));
+ status = PR_Connect(clientSock, &serverAddr, PR_INTERVAL_NO_TIMEOUT);
+ if (PR_FAILURE == status) {
+ fprintf(stderr, "PR_Connect failed\n");
+ exit(1);
+ }
+ nbytes = PR_Read(clientSock, buf, sizeof(buf));
+ if (nbytes != 0) {
+ fprintf(stderr, "expected 0 bytes but got %d bytes\n", nbytes);
+ exit(1);
+ }
+ status = PR_Close(clientSock);
+ if (PR_FAILURE == status) {
+ fprintf(stderr, "PR_Close failed\n");
+ exit(1);
+ }
+ printf("sleeping one second before shutting down server threads\n");
+ fflush(stdout);
+ PR_Sleep(PR_SecondsToInterval(1));
+
+ exit_flag = PR_TRUE;
+ status = PR_Interrupt(dummyThread);
+ if (PR_FAILURE == status) {
+ fprintf(stderr, "PR_Interrupt failed\n");
+ exit(1);
+ }
+ status = PR_JoinThread(dummyThread);
+ if (PR_FAILURE == status) {
+ fprintf(stderr, "PR_JoinThread failed\n");
+ exit(1);
+ }
+ for (idx = 0; idx < num_server_threads; idx++) {
+ status = PR_Interrupt(serverThreads[idx]);
+ if (PR_FAILURE == status) {
+ fprintf(stderr, "PR_Interrupt failed\n");
+ exit(1);
+ }
+ status = PR_JoinThread(serverThreads[idx]);
+ if (PR_FAILURE == status) {
+ fprintf(stderr, "PR_JoinThread failed\n");
+ exit(1);
+ }
+ }
+ PR_Free(serverThreads);
+ status = PR_Close(dummySock);
+ if (PR_FAILURE == status) {
+ fprintf(stderr, "PR_Close failed\n");
+ exit(1);
+ }
+ status = PR_Close(listenSock);
+ if (PR_FAILURE == status) {
+ fprintf(stderr, "PR_Close failed\n");
+ exit(1);
+ }
+
+ printf("PASS\n");
+ return 0;
+}
diff --git a/nsprpub/pr/tests/multiwait.c b/nsprpub/pr/tests/multiwait.c
new file mode 100644
index 0000000000..62a07f0428
--- /dev/null
+++ b/nsprpub/pr/tests/multiwait.c
@@ -0,0 +1,785 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "prio.h"
+#include "prprf.h"
+#include "prlog.h"
+#include "prmem.h"
+#include "pratom.h"
+#include "prlock.h"
+#include "prmwait.h"
+#include "prclist.h"
+#include "prerror.h"
+#include "prinrval.h"
+#include "prnetdb.h"
+#include "prthread.h"
+
+#include "plstr.h"
+#include "plerror.h"
+#include "plgetopt.h"
+
+#include <string.h>
+
+typedef struct Shared
+{
+ const char *title;
+ PRLock *list_lock;
+ PRWaitGroup *group;
+ PRIntervalTime timeout;
+} Shared;
+
+typedef enum Verbosity {silent, quiet, chatty, noisy} Verbosity;
+
+#ifdef DEBUG
+#define PORT_INC_DO +100
+#else
+#define PORT_INC_DO
+#endif
+#ifdef IS_64
+#define PORT_INC_3264 +200
+#else
+#define PORT_INC_3264
+#endif
+
+static PRFileDesc *debug = NULL;
+static PRInt32 desc_allocated = 0;
+static PRUint16 default_port = 12273 PORT_INC_DO PORT_INC_3264;
+static enum Verbosity verbosity = quiet;
+static PRInt32 ops_required = 1000, ops_done = 0;
+static PRThreadScope thread_scope = PR_LOCAL_THREAD;
+static PRIntn client_threads = 20, worker_threads = 2, wait_objects = 50;
+
+#if defined(DEBUG)
+#define MW_ASSERT(_expr) \
+ ((_expr)?((void)0):_MW_Assert(# _expr,__FILE__,__LINE__))
+static void _MW_Assert(const char *s, const char *file, PRIntn ln)
+{
+ if (NULL != debug) {
+ PL_FPrintError(debug, NULL);
+ }
+ PR_Assert(s, file, ln);
+} /* _MW_Assert */
+#else
+#define MW_ASSERT(_expr)
+#endif
+
+static void PrintRecvDesc(PRRecvWait *desc, const char *msg)
+{
+ const char *tag[] = {
+ "PR_MW_INTERRUPT", "PR_MW_TIMEOUT",
+ "PR_MW_FAILURE", "PR_MW_SUCCESS", "PR_MW_PENDING"
+ };
+ PR_fprintf(
+ debug, "%s: PRRecvWait(@0x%x): {fd: 0x%x, outcome: %s, tmo: %u}\n",
+ msg, desc, desc->fd, tag[desc->outcome + 3], desc->timeout);
+} /* PrintRecvDesc */
+
+static Shared *MakeShared(const char *title)
+{
+ Shared *shared = PR_NEWZAP(Shared);
+ shared->group = PR_CreateWaitGroup(1);
+ shared->timeout = PR_SecondsToInterval(1);
+ shared->list_lock = PR_NewLock();
+ shared->title = title;
+ return shared;
+} /* MakeShared */
+
+static void DestroyShared(Shared *shared)
+{
+ PRStatus rv;
+ if (verbosity > quiet) {
+ PR_fprintf(debug, "%s: destroying group\n", shared->title);
+ }
+ rv = PR_DestroyWaitGroup(shared->group);
+ MW_ASSERT(PR_SUCCESS == rv);
+ PR_DestroyLock(shared->list_lock);
+ PR_DELETE(shared);
+} /* DestroyShared */
+
+static PRRecvWait *CreateRecvWait(PRFileDesc *fd, PRIntervalTime timeout)
+{
+ PRRecvWait *desc_out = PR_NEWZAP(PRRecvWait);
+ MW_ASSERT(NULL != desc_out);
+
+ MW_ASSERT(NULL != fd);
+ desc_out->fd = fd;
+ desc_out->timeout = timeout;
+ desc_out->buffer.length = 120;
+ desc_out->buffer.start = PR_CALLOC(120);
+
+ PR_AtomicIncrement(&desc_allocated);
+
+ if (verbosity > chatty) {
+ PrintRecvDesc(desc_out, "Allocated");
+ }
+ return desc_out;
+} /* CreateRecvWait */
+
+static void DestroyRecvWait(PRRecvWait *desc_out)
+{
+ if (verbosity > chatty) {
+ PrintRecvDesc(desc_out, "Destroying");
+ }
+ PR_Close(desc_out->fd);
+ if (NULL != desc_out->buffer.start) {
+ PR_DELETE(desc_out->buffer.start);
+ }
+ PR_Free(desc_out);
+ (void)PR_AtomicDecrement(&desc_allocated);
+} /* DestroyRecvWait */
+
+static void CancelGroup(Shared *shared)
+{
+ PRRecvWait *desc_out;
+
+ if (verbosity > quiet) {
+ PR_fprintf(debug, "%s Reclaiming wait descriptors\n", shared->title);
+ }
+
+ do
+ {
+ desc_out = PR_CancelWaitGroup(shared->group);
+ if (NULL != desc_out) {
+ DestroyRecvWait(desc_out);
+ }
+ } while (NULL != desc_out);
+
+ MW_ASSERT(0 == desc_allocated);
+ MW_ASSERT(PR_GROUP_EMPTY_ERROR == PR_GetError());
+} /* CancelGroup */
+
+static void PR_CALLBACK ClientThread(void* arg)
+{
+ PRStatus rv;
+ PRInt32 bytes;
+ PRIntn empty_flags = 0;
+ PRNetAddr server_address;
+ unsigned char buffer[100];
+ Shared *shared = (Shared*)arg;
+ PRFileDesc *server = PR_NewTCPSocket();
+ if ((NULL == server)
+ && (PR_PENDING_INTERRUPT_ERROR == PR_GetError())) {
+ return;
+ }
+ MW_ASSERT(NULL != server);
+
+ if (verbosity > chatty) {
+ PR_fprintf(debug, "%s: Server socket @0x%x\n", shared->title, server);
+ }
+
+ /* Initialize the buffer so that Purify won't complain */
+ memset(buffer, 0, sizeof(buffer));
+
+ rv = PR_InitializeNetAddr(PR_IpAddrLoopback, default_port, &server_address);
+ MW_ASSERT(PR_SUCCESS == rv);
+
+ if (verbosity > quiet) {
+ PR_fprintf(debug, "%s: Client opening connection\n", shared->title);
+ }
+ rv = PR_Connect(server, &server_address, PR_INTERVAL_NO_TIMEOUT);
+
+ if (PR_FAILURE == rv)
+ {
+ if (verbosity > silent) {
+ PL_FPrintError(debug, "Client connect failed");
+ }
+ return;
+ }
+
+ while (ops_done < ops_required)
+ {
+ bytes = PR_Send(
+ server, buffer, sizeof(buffer), empty_flags, PR_INTERVAL_NO_TIMEOUT);
+ if ((-1 == bytes) && (PR_PENDING_INTERRUPT_ERROR == PR_GetError())) {
+ break;
+ }
+ MW_ASSERT(sizeof(buffer) == bytes);
+ if (verbosity > chatty)
+ PR_fprintf(
+ debug, "%s: Client sent %d bytes\n",
+ shared->title, sizeof(buffer));
+ bytes = PR_Recv(
+ server, buffer, sizeof(buffer), empty_flags, PR_INTERVAL_NO_TIMEOUT);
+ if (verbosity > chatty)
+ PR_fprintf(
+ debug, "%s: Client received %d bytes\n",
+ shared->title, sizeof(buffer));
+ if ((-1 == bytes) && (PR_PENDING_INTERRUPT_ERROR == PR_GetError())) {
+ break;
+ }
+ MW_ASSERT(sizeof(buffer) == bytes);
+ PR_Sleep(shared->timeout);
+ }
+ rv = PR_Close(server);
+ MW_ASSERT(PR_SUCCESS == rv);
+
+} /* ClientThread */
+
+static void OneInThenCancelled(Shared *shared)
+{
+ PRStatus rv;
+ PRRecvWait *desc_out, *desc_in = PR_NEWZAP(PRRecvWait);
+
+ shared->timeout = PR_INTERVAL_NO_TIMEOUT;
+
+ desc_in->fd = PR_NewTCPSocket();
+ desc_in->timeout = shared->timeout;
+
+ if (verbosity > chatty) {
+ PrintRecvDesc(desc_in, "Adding desc");
+ }
+
+ rv = PR_AddWaitFileDesc(shared->group, desc_in);
+ MW_ASSERT(PR_SUCCESS == rv);
+
+ if (verbosity > chatty) {
+ PrintRecvDesc(desc_in, "Cancelling");
+ }
+ rv = PR_CancelWaitFileDesc(shared->group, desc_in);
+ MW_ASSERT(PR_SUCCESS == rv);
+
+ desc_out = PR_WaitRecvReady(shared->group);
+ MW_ASSERT(desc_out == desc_in);
+ MW_ASSERT(PR_MW_INTERRUPT == desc_out->outcome);
+ MW_ASSERT(PR_PENDING_INTERRUPT_ERROR == PR_GetError());
+ if (verbosity > chatty) {
+ PrintRecvDesc(desc_out, "Ready");
+ }
+
+ rv = PR_Close(desc_in->fd);
+ MW_ASSERT(PR_SUCCESS == rv);
+
+ if (verbosity > quiet) {
+ PR_fprintf(debug, "%s: destroying group\n", shared->title);
+ }
+
+ PR_DELETE(desc_in);
+} /* OneInThenCancelled */
+
+static void OneOpOneThread(Shared *shared)
+{
+ PRStatus rv;
+ PRRecvWait *desc_out, *desc_in = PR_NEWZAP(PRRecvWait);
+
+ desc_in->fd = PR_NewTCPSocket();
+ desc_in->timeout = shared->timeout;
+
+ if (verbosity > chatty) {
+ PrintRecvDesc(desc_in, "Adding desc");
+ }
+
+ rv = PR_AddWaitFileDesc(shared->group, desc_in);
+ MW_ASSERT(PR_SUCCESS == rv);
+ desc_out = PR_WaitRecvReady(shared->group);
+ MW_ASSERT(desc_out == desc_in);
+ MW_ASSERT(PR_MW_TIMEOUT == desc_out->outcome);
+ MW_ASSERT(PR_IO_TIMEOUT_ERROR == PR_GetError());
+ if (verbosity > chatty) {
+ PrintRecvDesc(desc_out, "Ready");
+ }
+
+ rv = PR_Close(desc_in->fd);
+ MW_ASSERT(PR_SUCCESS == rv);
+
+ PR_DELETE(desc_in);
+} /* OneOpOneThread */
+
+static void ManyOpOneThread(Shared *shared)
+{
+ PRStatus rv;
+ PRIntn index;
+ PRRecvWait *desc_in;
+ PRRecvWait *desc_out;
+
+ if (verbosity > quiet) {
+ PR_fprintf(debug, "%s: adding %d descs\n", shared->title, wait_objects);
+ }
+
+ for (index = 0; index < wait_objects; ++index)
+ {
+ desc_in = CreateRecvWait(PR_NewTCPSocket(), shared->timeout);
+
+ rv = PR_AddWaitFileDesc(shared->group, desc_in);
+ MW_ASSERT(PR_SUCCESS == rv);
+ }
+
+ while (ops_done < ops_required)
+ {
+ desc_out = PR_WaitRecvReady(shared->group);
+ MW_ASSERT(PR_MW_TIMEOUT == desc_out->outcome);
+ MW_ASSERT(PR_IO_TIMEOUT_ERROR == PR_GetError());
+ if (verbosity > chatty) {
+ PrintRecvDesc(desc_out, "Ready/readding");
+ }
+ rv = PR_AddWaitFileDesc(shared->group, desc_out);
+ MW_ASSERT(PR_SUCCESS == rv);
+ (void)PR_AtomicIncrement(&ops_done);
+ }
+
+ CancelGroup(shared);
+} /* ManyOpOneThread */
+
+static void PR_CALLBACK SomeOpsThread(void *arg)
+{
+ PRRecvWait *desc_out;
+ PRStatus rv = PR_SUCCESS;
+ Shared *shared = (Shared*)arg;
+ do /* until interrupted */
+ {
+ desc_out = PR_WaitRecvReady(shared->group);
+ if (NULL == desc_out)
+ {
+ MW_ASSERT(PR_PENDING_INTERRUPT_ERROR == PR_GetError());
+ if (verbosity > quiet) {
+ PR_fprintf(debug, "Aborted\n");
+ }
+ break;
+ }
+ MW_ASSERT(PR_MW_TIMEOUT == desc_out->outcome);
+ MW_ASSERT(PR_IO_TIMEOUT_ERROR == PR_GetError());
+ if (verbosity > chatty) {
+ PrintRecvDesc(desc_out, "Ready");
+ }
+
+ if (verbosity > chatty) {
+ PrintRecvDesc(desc_out, "Re-Adding");
+ }
+ desc_out->timeout = shared->timeout;
+ rv = PR_AddWaitFileDesc(shared->group, desc_out);
+ PR_AtomicIncrement(&ops_done);
+ if (ops_done > ops_required) {
+ break;
+ }
+ } while (PR_SUCCESS == rv);
+ MW_ASSERT(PR_SUCCESS == rv);
+} /* SomeOpsThread */
+
+static void SomeOpsSomeThreads(Shared *shared)
+{
+ PRStatus rv;
+ PRThread **thread;
+ PRIntn index;
+ PRRecvWait *desc_in;
+
+ thread = (PRThread**)PR_CALLOC(sizeof(PRThread*) * worker_threads);
+
+ /* Create some threads */
+
+ if (verbosity > quiet) {
+ PR_fprintf(debug, "%s: creating threads\n", shared->title);
+ }
+ for (index = 0; index < worker_threads; ++index)
+ {
+ thread[index] = PR_CreateThread(
+ PR_USER_THREAD, SomeOpsThread, shared,
+ PR_PRIORITY_HIGH, thread_scope,
+ PR_JOINABLE_THREAD, 16 * 1024);
+ }
+
+ /* then create some operations */
+ if (verbosity > quiet) {
+ PR_fprintf(debug, "%s: creating desc\n", shared->title);
+ }
+ for (index = 0; index < wait_objects; ++index)
+ {
+ desc_in = CreateRecvWait(PR_NewTCPSocket(), shared->timeout);
+ rv = PR_AddWaitFileDesc(shared->group, desc_in);
+ MW_ASSERT(PR_SUCCESS == rv);
+ }
+
+ if (verbosity > quiet) {
+ PR_fprintf(debug, "%s: sleeping\n", shared->title);
+ }
+ while (ops_done < ops_required) {
+ PR_Sleep(shared->timeout);
+ }
+
+ if (verbosity > quiet) {
+ PR_fprintf(debug, "%s: interrupting/joining threads\n", shared->title);
+ }
+ for (index = 0; index < worker_threads; ++index)
+ {
+ rv = PR_Interrupt(thread[index]);
+ MW_ASSERT(PR_SUCCESS == rv);
+ rv = PR_JoinThread(thread[index]);
+ MW_ASSERT(PR_SUCCESS == rv);
+ }
+ PR_DELETE(thread);
+
+ CancelGroup(shared);
+} /* SomeOpsSomeThreads */
+
+static PRStatus ServiceRequest(Shared *shared, PRRecvWait *desc)
+{
+ PRInt32 bytes_out;
+
+ if (verbosity > chatty)
+ PR_fprintf(
+ debug, "%s: Service received %d bytes\n",
+ shared->title, desc->bytesRecv);
+
+ if (0 == desc->bytesRecv) {
+ goto quitting;
+ }
+ if ((-1 == desc->bytesRecv)
+ && (PR_PENDING_INTERRUPT_ERROR == PR_GetError())) {
+ goto aborted;
+ }
+
+ bytes_out = PR_Send(
+ desc->fd, desc->buffer.start, desc->bytesRecv, 0, shared->timeout);
+ if (verbosity > chatty)
+ PR_fprintf(
+ debug, "%s: Service sent %d bytes\n",
+ shared->title, bytes_out);
+
+ if ((-1 == bytes_out)
+ && (PR_PENDING_INTERRUPT_ERROR == PR_GetError())) {
+ goto aborted;
+ }
+ MW_ASSERT(bytes_out == desc->bytesRecv);
+
+ return PR_SUCCESS;
+
+aborted:
+quitting:
+ return PR_FAILURE;
+} /* ServiceRequest */
+
+static void PR_CALLBACK ServiceThread(void *arg)
+{
+ PRStatus rv = PR_SUCCESS;
+ PRRecvWait *desc_out = NULL;
+ Shared *shared = (Shared*)arg;
+ do /* until interrupted */
+ {
+ if (NULL != desc_out)
+ {
+ desc_out->timeout = PR_INTERVAL_NO_TIMEOUT;
+ if (verbosity > chatty) {
+ PrintRecvDesc(desc_out, "Service re-adding");
+ }
+ rv = PR_AddWaitFileDesc(shared->group, desc_out);
+ MW_ASSERT(PR_SUCCESS == rv);
+ }
+
+ desc_out = PR_WaitRecvReady(shared->group);
+ if (NULL == desc_out)
+ {
+ MW_ASSERT(PR_PENDING_INTERRUPT_ERROR == PR_GetError());
+ break;
+ }
+
+ switch (desc_out->outcome)
+ {
+ case PR_MW_SUCCESS:
+ {
+ PR_AtomicIncrement(&ops_done);
+ if (verbosity > chatty) {
+ PrintRecvDesc(desc_out, "Service ready");
+ }
+ rv = ServiceRequest(shared, desc_out);
+ break;
+ }
+ case PR_MW_INTERRUPT:
+ MW_ASSERT(PR_PENDING_INTERRUPT_ERROR == PR_GetError());
+ rv = PR_FAILURE; /* if interrupted, then exit */
+ break;
+ case PR_MW_TIMEOUT:
+ MW_ASSERT(PR_IO_TIMEOUT_ERROR == PR_GetError());
+ case PR_MW_FAILURE:
+ if (verbosity > silent) {
+ PL_FPrintError(debug, "RecvReady failure");
+ }
+ break;
+ default:
+ break;
+ }
+ } while (PR_SUCCESS == rv);
+
+ if (NULL != desc_out) {
+ DestroyRecvWait(desc_out);
+ }
+
+} /* ServiceThread */
+
+static void PR_CALLBACK EnumerationThread(void *arg)
+{
+ PRStatus rv;
+ PRIntn count;
+ PRRecvWait *desc;
+ Shared *shared = (Shared*)arg;
+ PRIntervalTime five_seconds = PR_SecondsToInterval(5);
+ PRMWaitEnumerator *enumerator = PR_CreateMWaitEnumerator(shared->group);
+ MW_ASSERT(NULL != enumerator);
+
+ while (PR_SUCCESS == PR_Sleep(five_seconds))
+ {
+ count = 0;
+ desc = NULL;
+ while (NULL != (desc = PR_EnumerateWaitGroup(enumerator, desc)))
+ {
+ if (verbosity > chatty) {
+ PrintRecvDesc(desc, shared->title);
+ }
+ count += 1;
+ }
+ if (verbosity > silent)
+ PR_fprintf(debug,
+ "%s Enumerated %d objects\n", shared->title, count);
+ }
+
+ MW_ASSERT(PR_PENDING_INTERRUPT_ERROR == PR_GetError());
+
+
+ rv = PR_DestroyMWaitEnumerator(enumerator);
+ MW_ASSERT(PR_SUCCESS == rv);
+} /* EnumerationThread */
+
+static void PR_CALLBACK ServerThread(void *arg)
+{
+ PRStatus rv;
+ PRIntn index;
+ PRRecvWait *desc_in;
+ PRThread **worker_thread;
+ Shared *shared = (Shared*)arg;
+ PRFileDesc *listener, *service;
+ PRNetAddr server_address, client_address;
+
+ worker_thread = (PRThread**)PR_CALLOC(sizeof(PRThread*) * worker_threads);
+ if (verbosity > quiet) {
+ PR_fprintf(debug, "%s: Server creating worker_threads\n", shared->title);
+ }
+ for (index = 0; index < worker_threads; ++index)
+ {
+ worker_thread[index] = PR_CreateThread(
+ PR_USER_THREAD, ServiceThread, shared,
+ PR_PRIORITY_HIGH, thread_scope,
+ PR_JOINABLE_THREAD, 16 * 1024);
+ }
+
+ rv = PR_InitializeNetAddr(PR_IpAddrAny, default_port, &server_address);
+ MW_ASSERT(PR_SUCCESS == rv);
+
+ listener = PR_NewTCPSocket(); MW_ASSERT(NULL != listener);
+ if (verbosity > chatty)
+ PR_fprintf(
+ debug, "%s: Server listener socket @0x%x\n",
+ shared->title, listener);
+ rv = PR_Bind(listener, &server_address); MW_ASSERT(PR_SUCCESS == rv);
+ rv = PR_Listen(listener, 10); MW_ASSERT(PR_SUCCESS == rv);
+ while (ops_done < ops_required)
+ {
+ if (verbosity > quiet) {
+ PR_fprintf(debug, "%s: Server accepting connection\n", shared->title);
+ }
+ service = PR_Accept(listener, &client_address, PR_INTERVAL_NO_TIMEOUT);
+ if (NULL == service)
+ {
+ if (PR_PENDING_INTERRUPT_ERROR == PR_GetError()) {
+ break;
+ }
+ PL_PrintError("Accept failed");
+ MW_ASSERT(PR_FALSE && "Accept failed");
+ }
+ else
+ {
+ desc_in = CreateRecvWait(service, shared->timeout);
+ desc_in->timeout = PR_INTERVAL_NO_TIMEOUT;
+ if (verbosity > chatty) {
+ PrintRecvDesc(desc_in, "Service adding");
+ }
+ rv = PR_AddWaitFileDesc(shared->group, desc_in);
+ MW_ASSERT(PR_SUCCESS == rv);
+ }
+ }
+
+ if (verbosity > quiet) {
+ PR_fprintf(debug, "%s: Server interrupting worker_threads\n", shared->title);
+ }
+ for (index = 0; index < worker_threads; ++index)
+ {
+ rv = PR_Interrupt(worker_thread[index]);
+ MW_ASSERT(PR_SUCCESS == rv);
+ rv = PR_JoinThread(worker_thread[index]);
+ MW_ASSERT(PR_SUCCESS == rv);
+ }
+ PR_DELETE(worker_thread);
+
+ PR_Close(listener);
+
+ CancelGroup(shared);
+
+} /* ServerThread */
+
+static void RealOneGroupIO(Shared *shared)
+{
+ /*
+ ** Create a server that listens for connections and then services
+ ** requests that come in over those connections. The server never
+ ** deletes a connection and assumes a basic RPC model of operation.
+ **
+ ** Use worker_threads threads to service how every many open ports
+ ** there might be.
+ **
+ ** Oh, ya. Almost forget. Create (some) clients as well.
+ */
+ PRStatus rv;
+ PRIntn index;
+ PRThread *server_thread, *enumeration_thread, **client_thread;
+
+ if (verbosity > quiet) {
+ PR_fprintf(debug, "%s: creating server_thread\n", shared->title);
+ }
+
+ server_thread = PR_CreateThread(
+ PR_USER_THREAD, ServerThread, shared,
+ PR_PRIORITY_HIGH, thread_scope,
+ PR_JOINABLE_THREAD, 16 * 1024);
+
+ if (verbosity > quiet) {
+ PR_fprintf(debug, "%s: creating enumeration_thread\n", shared->title);
+ }
+
+ enumeration_thread = PR_CreateThread(
+ PR_USER_THREAD, EnumerationThread, shared,
+ PR_PRIORITY_HIGH, thread_scope,
+ PR_JOINABLE_THREAD, 16 * 1024);
+
+ if (verbosity > quiet) {
+ PR_fprintf(debug, "%s: snoozing before creating clients\n", shared->title);
+ }
+ PR_Sleep(5 * shared->timeout);
+
+ if (verbosity > quiet) {
+ PR_fprintf(debug, "%s: creating client_threads\n", shared->title);
+ }
+ client_thread = (PRThread**)PR_CALLOC(sizeof(PRThread*) * client_threads);
+ for (index = 0; index < client_threads; ++index)
+ {
+ client_thread[index] = PR_CreateThread(
+ PR_USER_THREAD, ClientThread, shared,
+ PR_PRIORITY_NORMAL, thread_scope,
+ PR_JOINABLE_THREAD, 16 * 1024);
+ }
+
+ while (ops_done < ops_required) {
+ PR_Sleep(shared->timeout);
+ }
+
+ if (verbosity > quiet) {
+ PR_fprintf(debug, "%s: interrupting/joining client_threads\n", shared->title);
+ }
+ for (index = 0; index < client_threads; ++index)
+ {
+ rv = PR_Interrupt(client_thread[index]);
+ MW_ASSERT(PR_SUCCESS == rv);
+ rv = PR_JoinThread(client_thread[index]);
+ MW_ASSERT(PR_SUCCESS == rv);
+ }
+ PR_DELETE(client_thread);
+
+ if (verbosity > quiet) {
+ PR_fprintf(debug, "%s: interrupting/joining enumeration_thread\n", shared->title);
+ }
+ rv = PR_Interrupt(enumeration_thread);
+ MW_ASSERT(PR_SUCCESS == rv);
+ rv = PR_JoinThread(enumeration_thread);
+ MW_ASSERT(PR_SUCCESS == rv);
+
+ if (verbosity > quiet) {
+ PR_fprintf(debug, "%s: interrupting/joining server_thread\n", shared->title);
+ }
+ rv = PR_Interrupt(server_thread);
+ MW_ASSERT(PR_SUCCESS == rv);
+ rv = PR_JoinThread(server_thread);
+ MW_ASSERT(PR_SUCCESS == rv);
+} /* RealOneGroupIO */
+
+static void RunThisOne(
+ void (*func)(Shared*), const char *name, const char *test_name)
+{
+ Shared *shared;
+ if ((NULL == test_name) || (0 == PL_strcmp(name, test_name)))
+ {
+ if (verbosity > silent) {
+ PR_fprintf(debug, "%s()\n", name);
+ }
+ shared = MakeShared(name);
+ ops_done = 0;
+ func(shared); /* run the test */
+ MW_ASSERT(0 == desc_allocated);
+ DestroyShared(shared);
+ }
+} /* RunThisOne */
+
+static Verbosity ChangeVerbosity(Verbosity verbosity, PRIntn delta)
+{
+ return (Verbosity)(((PRIntn)verbosity) + delta);
+} /* ChangeVerbosity */
+
+int main(int argc, char **argv)
+{
+ PLOptStatus os;
+ const char *test_name = NULL;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "dqGc:o:p:t:w:");
+
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 0:
+ test_name = opt->value;
+ break;
+ case 'd': /* debug mode */
+ if (verbosity < noisy) {
+ verbosity = ChangeVerbosity(verbosity, 1);
+ }
+ break;
+ case 'q': /* debug mode */
+ if (verbosity > silent) {
+ verbosity = ChangeVerbosity(verbosity, -1);
+ }
+ break;
+ case 'G': /* use global threads */
+ thread_scope = PR_GLOBAL_THREAD;
+ break;
+ case 'c': /* number of client threads */
+ client_threads = atoi(opt->value);
+ break;
+ case 'o': /* operations to compelete */
+ ops_required = atoi(opt->value);
+ break;
+ case 'p': /* default port */
+ default_port = atoi(opt->value);
+ break;
+ case 't': /* number of threads waiting */
+ worker_threads = atoi(opt->value);
+ break;
+ case 'w': /* number of wait objects */
+ wait_objects = atoi(opt->value);
+ break;
+ default:
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ if (verbosity > 0) {
+ debug = PR_GetSpecialFD(PR_StandardError);
+ }
+
+ RunThisOne(OneInThenCancelled, "OneInThenCancelled", test_name);
+ RunThisOne(OneOpOneThread, "OneOpOneThread", test_name);
+ RunThisOne(ManyOpOneThread, "ManyOpOneThread", test_name);
+ RunThisOne(SomeOpsSomeThreads, "SomeOpsSomeThreads", test_name);
+ RunThisOne(RealOneGroupIO, "RealOneGroupIO", test_name);
+ return 0;
+} /* main */
+
+/* multwait.c */
diff --git a/nsprpub/pr/tests/nameshm1.c b/nsprpub/pr/tests/nameshm1.c
new file mode 100644
index 0000000000..ca24b4e813
--- /dev/null
+++ b/nsprpub/pr/tests/nameshm1.c
@@ -0,0 +1,586 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+** 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>
+
+#ifdef DEBUG
+#define SEM_D "D"
+#else
+#define SEM_D
+#endif
+#ifdef IS_64
+#define SEM_64 "64"
+#else
+#define SEM_64
+#endif
+
+#define SEM_NAME1 "/tmp/nameshmSEM1" SEM_D SEM_64
+#define SEM_NAME2 "/tmp/nameshmSEM2" SEM_D SEM_64
+#define OPT_NAME "/tmp/xxxNSPRshm" SEM_D SEM_64
+#define EXE_NAME "nameshm1"
+#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] = OPT_NAME;
+
+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] = EXE_NAME;
+ 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() */
+
+int main(int 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/nsprpub/pr/tests/nbconn.c b/nsprpub/pr/tests/nbconn.c
new file mode 100644
index 0000000000..d1dd67c042
--- /dev/null
+++ b/nsprpub/pr/tests/nbconn.c
@@ -0,0 +1,531 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * A test for nonblocking connect. Functions tested include PR_Connect,
+ * PR_Poll, and PR_GetConnectStatus.
+ *
+ * The test should be invoked with a host name, for example:
+ * nbconn www.netscape.com
+ * It will do a nonblocking connect to port 80 (HTTP) on that host,
+ * and when connected, issue the "GET /" HTTP command.
+ *
+ * You should run this test in three ways:
+ * 1. To a known web site, such as www.netscape.com. The HTML of the
+ * top-level page at the web site should be printed.
+ * 2. To a machine not running a web server at port 80. This test should
+ * fail. Ideally the error code should be PR_CONNECT_REFUSED_ERROR.
+ * But it is possible to return PR_UNKNOWN_ERROR on certain platforms.
+ * 3. To an unreachable machine, for example, a machine that is off line.
+ * The test should fail after the connect times out. Ideally the
+ * error code should be PR_IO_TIMEOUT_ERROR, but it is possible to
+ * return PR_UNKNOWN_ERROR on certain platforms.
+ */
+
+#include "nspr.h"
+#include "plgetopt.h"
+#include <stdio.h>
+#include <string.h>
+
+#define SERVER_MAX_BIND_COUNT 100
+#define DATA_BUF_SIZE 256
+#define TCP_SERVER_PORT 10000
+#define TCP_UNUSED_PORT 211
+
+typedef struct Server_Param {
+ PRFileDesc *sp_fd; /* server port */
+} Server_Param;
+static void PR_CALLBACK TCP_Server(void *arg);
+
+int _debug_on;
+#define DPRINTF(arg) if (_debug_on) printf arg
+
+static PRIntn connection_success_test();
+static PRIntn connection_failure_test();
+
+int main(int argc, char **argv)
+{
+ PRHostEnt he;
+ char buf[1024];
+ PRNetAddr addr;
+ PRPollDesc pd;
+ PRStatus rv;
+ PRSocketOptionData optData;
+ const char *hostname = NULL;
+ PRIntn default_case, n, bytes_read, bytes_sent;
+ PRInt32 failed_already = 0;
+
+ /*
+ * -d debug mode
+ */
+
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "d");
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 0: /* debug mode */
+ hostname = opt->value;
+ break;
+ case 'd': /* debug mode */
+ _debug_on = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ PR_STDIO_INIT();
+ if (hostname) {
+ default_case = 0;
+ }
+ else {
+ default_case = 1;
+ }
+
+ if (default_case) {
+
+ /*
+ * In the default case the following tests are executed:
+ * 1. successful connection: a server thread accepts a connection
+ * from the main thread
+ * 2. unsuccessful connection: the main thread tries to connect to a
+ * nonexistent port and expects to get an error
+ */
+ rv = connection_success_test();
+ if (rv == 0) {
+ rv = connection_failure_test();
+ }
+ return rv;
+ } else {
+ PRFileDesc *sock;
+
+ if (PR_GetHostByName(argv[1], buf, sizeof(buf), &he) == PR_FAILURE) {
+ printf( "Unknown host: %s\n", argv[1]);
+ exit(1);
+ } else {
+ printf( "host: %s\n", buf);
+ }
+ PR_EnumerateHostEnt(0, &he, 80, &addr);
+
+ sock = PR_NewTCPSocket();
+ optData.option = PR_SockOpt_Nonblocking;
+ optData.value.non_blocking = PR_TRUE;
+ PR_SetSocketOption(sock, &optData);
+ rv = PR_Connect(sock, &addr, PR_INTERVAL_NO_TIMEOUT);
+ if (rv == PR_FAILURE && PR_GetError() == PR_IN_PROGRESS_ERROR) {
+ printf( "Connect in progress\n");
+ }
+
+ pd.fd = sock;
+ pd.in_flags = PR_POLL_WRITE | PR_POLL_EXCEPT;
+ n = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT);
+ if (n == -1) {
+ printf( "PR_Poll failed\n");
+ exit(1);
+ }
+ printf( "PR_Poll returns %d\n", n);
+ if (pd.out_flags & PR_POLL_READ) {
+ printf( "PR_POLL_READ\n");
+ }
+ if (pd.out_flags & PR_POLL_WRITE) {
+ printf( "PR_POLL_WRITE\n");
+ }
+ if (pd.out_flags & PR_POLL_EXCEPT) {
+ printf( "PR_POLL_EXCEPT\n");
+ }
+ if (pd.out_flags & PR_POLL_ERR) {
+ printf( "PR_POLL_ERR\n");
+ }
+ if (pd.out_flags & PR_POLL_NVAL) {
+ printf( "PR_POLL_NVAL\n");
+ }
+
+ if (PR_GetConnectStatus(&pd) == PR_SUCCESS) {
+ printf("PR_GetConnectStatus: connect succeeded\n");
+ PR_Write(sock, "GET /\r\n\r\n", 9);
+ PR_Shutdown(sock, PR_SHUTDOWN_SEND);
+ pd.in_flags = PR_POLL_READ;
+ while (1) {
+ n = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT);
+ printf( "poll returns %d\n", n);
+ n = PR_Read(sock, buf, sizeof(buf));
+ printf( "read returns %d\n", n);
+ if (n <= 0) {
+ break;
+ }
+ PR_Write(PR_STDOUT, buf, n);
+ }
+ } else {
+ if (PR_GetError() == PR_IN_PROGRESS_ERROR) {
+ printf( "PR_GetConnectStatus: connect still in progress\n");
+ exit(1);
+ }
+ printf( "PR_GetConnectStatus: connect failed: (%ld, %ld)\n",
+ PR_GetError(), PR_GetOSError());
+ }
+ PR_Close(sock);
+ printf( "PASS\n");
+ return 0;
+
+ }
+}
+
+
+/*
+ * TCP Server
+ * Server Thread
+ * Accept a connection from the client and write some data
+ */
+static void PR_CALLBACK
+TCP_Server(void *arg)
+{
+ Server_Param *sp = (Server_Param *) arg;
+ PRFileDesc *sockfd, *newsockfd;
+ char data_buf[DATA_BUF_SIZE];
+ PRIntn rv, bytes_read;
+
+ sockfd = sp->sp_fd;
+ if ((newsockfd = PR_Accept(sockfd, NULL,
+ PR_INTERVAL_NO_TIMEOUT)) == NULL) {
+ fprintf(stderr,"ERROR - PR_Accept failed: (%d,%d)\n",
+ PR_GetError(), PR_GetOSError());
+ return;
+ }
+ bytes_read = 0;
+ while (bytes_read != DATA_BUF_SIZE) {
+ rv = PR_Read(newsockfd, data_buf + bytes_read,
+ DATA_BUF_SIZE - bytes_read);
+ if (rv < 0) {
+ fprintf(stderr,"Error - PR_Read failed: (%d, %d)\n",
+ PR_GetError(), PR_GetOSError());
+ PR_Close(newsockfd);
+ return;
+ }
+ PR_ASSERT(rv != 0);
+ bytes_read += rv;
+ }
+ DPRINTF(("Bytes read from client - %d\n",bytes_read));
+ rv = PR_Write(newsockfd, data_buf,DATA_BUF_SIZE);
+ if (rv < 0) {
+ fprintf(stderr,"Error - PR_Write failed: (%d, %d)\n",
+ PR_GetError(), PR_GetOSError());
+ PR_Close(newsockfd);
+ return;
+ }
+ PR_ASSERT(rv == DATA_BUF_SIZE);
+ DPRINTF(("Bytes written to client - %d\n",rv));
+ PR_Close(newsockfd);
+}
+
+
+/*
+ * test for successful connection using a non-blocking socket
+ */
+static PRIntn
+connection_success_test()
+{
+ PRFileDesc *sockfd = NULL, *conn_fd = NULL;
+ PRNetAddr netaddr;
+ PRInt32 i, rv;
+ PRPollDesc pd;
+ PRSocketOptionData optData;
+ PRThread *thr = NULL;
+ Server_Param sp;
+ char send_buf[DATA_BUF_SIZE], recv_buf[DATA_BUF_SIZE];
+ PRIntn default_case, n, bytes_read, bytes_sent;
+ PRIntn failed_already = 0;
+
+ /*
+ * Create a tcp socket
+ */
+ if ((sockfd = PR_NewTCPSocket()) == NULL) {
+ fprintf(stderr,"Error - PR_NewTCPSocket failed\n");
+ failed_already=1;
+ goto def_exit;
+ }
+ memset(&netaddr, 0, sizeof(netaddr));
+ netaddr.inet.family = PR_AF_INET;
+ netaddr.inet.port = PR_htons(TCP_SERVER_PORT);
+ netaddr.inet.ip = PR_htonl(PR_INADDR_ANY);
+ /*
+ * try a few times to bind server's address, if addresses are in
+ * use
+ */
+ i = 0;
+ while (PR_Bind(sockfd, &netaddr) < 0) {
+ if (PR_GetError() == PR_ADDRESS_IN_USE_ERROR) {
+ netaddr.inet.port += 2;
+ if (i++ < SERVER_MAX_BIND_COUNT) {
+ continue;
+ }
+ }
+ fprintf(stderr,"ERROR - PR_Bind failed: (%d,%d)\n",
+ PR_GetError(), PR_GetOSError());
+ failed_already=1;
+ goto def_exit;
+ }
+
+ if (PR_Listen(sockfd, 32) < 0) {
+ fprintf(stderr,"ERROR - PR_Listen failed: (%d,%d)\n",
+ PR_GetError(), PR_GetOSError());
+ failed_already=1;
+ goto def_exit;
+ }
+
+ if (PR_GetSockName(sockfd, &netaddr) < 0) {
+ fprintf(stderr,"ERROR - PR_GetSockName failed: (%d,%d)\n",
+ PR_GetError(), PR_GetOSError());
+ failed_already=1;
+ goto def_exit;
+ }
+ if ((conn_fd = PR_NewTCPSocket()) == NULL) {
+ fprintf(stderr,"Error - PR_NewTCPSocket failed\n");
+ failed_already=1;
+ goto def_exit;
+ }
+ optData.option = PR_SockOpt_Nonblocking;
+ optData.value.non_blocking = PR_TRUE;
+ PR_SetSocketOption(conn_fd, &optData);
+ rv = PR_Connect(conn_fd, &netaddr, PR_INTERVAL_NO_TIMEOUT);
+ if (rv == PR_FAILURE) {
+ if (PR_GetError() == PR_IN_PROGRESS_ERROR) {
+ DPRINTF(("Connect in progress\n"));
+ } else {
+ fprintf(stderr,"Error - PR_Connect failed: (%d, %d)\n",
+ PR_GetError(), PR_GetOSError());
+ failed_already=1;
+ goto def_exit;
+ }
+ }
+ /*
+ * Now create a thread to accept a connection
+ */
+ sp.sp_fd = sockfd;
+ thr = PR_CreateThread(PR_USER_THREAD, TCP_Server, (void *)&sp,
+ PR_PRIORITY_NORMAL, PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0);
+ if (thr == NULL) {
+ fprintf(stderr,"Error - PR_CreateThread failed: (%d,%d)\n",
+ PR_GetError(), PR_GetOSError());
+ failed_already=1;
+ goto def_exit;
+ }
+ DPRINTF(("Created TCP_Server thread [0x%x]\n",thr));
+ pd.fd = conn_fd;
+ pd.in_flags = PR_POLL_WRITE | PR_POLL_EXCEPT;
+ n = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT);
+ if (n == -1) {
+ fprintf(stderr,"Error - PR_Poll failed: (%d, %d)\n",
+ PR_GetError(), PR_GetOSError());
+ failed_already=1;
+ goto def_exit;
+ }
+ if (PR_GetConnectStatus(&pd) == PR_SUCCESS) {
+ PRInt32 rv;
+
+ DPRINTF(("Connection successful\n"));
+
+ /*
+ * Write some data, read it back and check data integrity to
+ * make sure the connection is good
+ */
+ pd.in_flags = PR_POLL_WRITE;
+ bytes_sent = 0;
+ memset(send_buf, 'a', DATA_BUF_SIZE);
+ while (bytes_sent != DATA_BUF_SIZE) {
+ rv = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT);
+ if (rv < 0) {
+ fprintf(stderr,"Error - PR_Poll failed: (%d, %d)\n",
+ PR_GetError(), PR_GetOSError());
+ failed_already=1;
+ goto def_exit;
+ }
+ PR_ASSERT((rv == 1) && (pd.out_flags == PR_POLL_WRITE));
+ rv = PR_Write(conn_fd, send_buf + bytes_sent,
+ DATA_BUF_SIZE - bytes_sent);
+ if (rv < 0) {
+ fprintf(stderr,"Error - PR_Write failed: (%d, %d)\n",
+ PR_GetError(), PR_GetOSError());
+ failed_already=1;
+ goto def_exit;
+ }
+ PR_ASSERT(rv > 0);
+ bytes_sent += rv;
+ }
+ DPRINTF(("Bytes written to server - %d\n",bytes_sent));
+ PR_Shutdown(conn_fd, PR_SHUTDOWN_SEND);
+ pd.in_flags = PR_POLL_READ;
+ bytes_read = 0;
+ memset(recv_buf, 0, DATA_BUF_SIZE);
+ while (bytes_read != DATA_BUF_SIZE) {
+ rv = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT);
+ if (rv < 0) {
+ fprintf(stderr,"Error - PR_Poll failed: (%d, %d)\n",
+ PR_GetError(), PR_GetOSError());
+ failed_already=1;
+ goto def_exit;
+ }
+ PR_ASSERT((rv == 1) && (pd.out_flags == PR_POLL_READ));
+ rv = PR_Read(conn_fd, recv_buf + bytes_read,
+ DATA_BUF_SIZE - bytes_read);
+ if (rv < 0) {
+ fprintf(stderr,"Error - PR_Read failed: (%d, %d)\n",
+ PR_GetError(), PR_GetOSError());
+ failed_already=1;
+ goto def_exit;
+ }
+ PR_ASSERT(rv != 0);
+ bytes_read += rv;
+ }
+ DPRINTF(("Bytes read from server - %d\n",bytes_read));
+ /*
+ * verify the data read
+ */
+ if (memcmp(send_buf, recv_buf, DATA_BUF_SIZE) != 0) {
+ fprintf(stderr,"ERROR - data corruption\n");
+ failed_already=1;
+ goto def_exit;
+ }
+ DPRINTF(("Data integrity verified\n"));
+ } else {
+ fprintf(stderr,"PR_GetConnectStatus: connect failed: (%ld, %ld)\n",
+ PR_GetError(), PR_GetOSError());
+ failed_already = 1;
+ goto def_exit;
+ }
+def_exit:
+ if (thr) {
+ PR_JoinThread(thr);
+ thr = NULL;
+ }
+ if (sockfd) {
+ PR_Close(sockfd);
+ sockfd = NULL;
+ }
+ if (conn_fd) {
+ PR_Close(conn_fd);
+ conn_fd = NULL;
+ }
+ if (failed_already) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+
+}
+
+/*
+ * test for connection to a nonexistent port using a non-blocking socket
+ */
+static PRIntn
+connection_failure_test()
+{
+ PRFileDesc *sockfd = NULL, *conn_fd = NULL;
+ PRNetAddr netaddr;
+ PRInt32 i, rv;
+ PRPollDesc pd;
+ PRSocketOptionData optData;
+ PRIntn n, failed_already = 0;
+
+ /*
+ * Create a tcp socket
+ */
+ if ((sockfd = PR_NewTCPSocket()) == NULL) {
+ fprintf(stderr,"Error - PR_NewTCPSocket failed\n");
+ failed_already=1;
+ goto def_exit;
+ }
+ memset(&netaddr, 0, sizeof(netaddr));
+ netaddr.inet.family = PR_AF_INET;
+ netaddr.inet.port = PR_htons(TCP_SERVER_PORT);
+ netaddr.inet.ip = PR_htonl(PR_INADDR_ANY);
+ /*
+ * try a few times to bind server's address, if addresses are in
+ * use
+ */
+ i = 0;
+ while (PR_Bind(sockfd, &netaddr) < 0) {
+ if (PR_GetError() == PR_ADDRESS_IN_USE_ERROR) {
+ netaddr.inet.port += 2;
+ if (i++ < SERVER_MAX_BIND_COUNT) {
+ continue;
+ }
+ }
+ fprintf(stderr,"ERROR - PR_Bind failed: (%d,%d)\n",
+ PR_GetError(), PR_GetOSError());
+ failed_already=1;
+ goto def_exit;
+ }
+
+ if (PR_GetSockName(sockfd, &netaddr) < 0) {
+ fprintf(stderr,"ERROR - PR_GetSockName failed: (%d,%d)\n",
+ PR_GetError(), PR_GetOSError());
+ failed_already=1;
+ goto def_exit;
+ }
+#ifdef AIX
+ /*
+ * On AIX, set to unused/reserved port
+ */
+ netaddr.inet.port = PR_htons(TCP_UNUSED_PORT);
+#endif
+ if ((conn_fd = PR_NewTCPSocket()) == NULL) {
+ fprintf(stderr,"Error - PR_NewTCPSocket failed\n");
+ failed_already=1;
+ goto def_exit;
+ }
+ optData.option = PR_SockOpt_Nonblocking;
+ optData.value.non_blocking = PR_TRUE;
+ PR_SetSocketOption(conn_fd, &optData);
+ rv = PR_Connect(conn_fd, &netaddr, PR_INTERVAL_NO_TIMEOUT);
+ if (rv == PR_FAILURE) {
+ DPRINTF(("PR_Connect to a non-listen port failed: (%d, %d)\n",
+ PR_GetError(), PR_GetOSError()));
+ } else {
+ PR_ASSERT(rv == PR_SUCCESS);
+ fprintf(stderr,"Error - PR_Connect succeeded, expected to fail\n");
+ failed_already=1;
+ goto def_exit;
+ }
+ pd.fd = conn_fd;
+ pd.in_flags = PR_POLL_WRITE | PR_POLL_EXCEPT;
+ n = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT);
+ if (n == -1) {
+ fprintf(stderr,"Error - PR_Poll failed: (%d, %d)\n",
+ PR_GetError(), PR_GetOSError());
+ failed_already=1;
+ goto def_exit;
+ }
+ if (PR_GetConnectStatus(&pd) == PR_SUCCESS) {
+ PRInt32 rv;
+ fprintf(stderr,"PR_GetConnectStatus succeeded, expected to fail\n");
+ failed_already = 1;
+ goto def_exit;
+ }
+ rv = PR_GetError();
+ DPRINTF(("Connection failed, successfully with PR_Error %d\n",rv));
+def_exit:
+ if (sockfd) {
+ PR_Close(sockfd);
+ sockfd = NULL;
+ }
+ if (conn_fd) {
+ PR_Close(conn_fd);
+ conn_fd = NULL;
+ }
+ if (failed_already) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+
+}
diff --git a/nsprpub/pr/tests/nblayer.c b/nsprpub/pr/tests/nblayer.c
new file mode 100644
index 0000000000..9459866972
--- /dev/null
+++ b/nsprpub/pr/tests/nblayer.c
@@ -0,0 +1,778 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "prio.h"
+#include "prmem.h"
+#include "prprf.h"
+#include "prlog.h"
+#include "prerror.h"
+#include "prnetdb.h"
+#include "prthread.h"
+
+#include "plerror.h"
+#include "plgetopt.h"
+#include "prwin16.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+/*
+** Testing layering of I/O
+**
+** The layered server
+** A thread that acts as a server. It creates a TCP listener with a dummy
+** layer pushed on top. Then listens for incoming connections. Each connection
+** request for connection will be layered as well, accept one request, echo
+** it back and close.
+**
+** The layered client
+** Pretty much what you'd expect.
+*/
+
+static PRFileDesc *logFile;
+static PRDescIdentity identity;
+static PRNetAddr server_address;
+
+static PRIOMethods myMethods;
+
+typedef enum {rcv_get_debit, rcv_send_credit, rcv_data} RcvState;
+typedef enum {xmt_send_debit, xmt_recv_credit, xmt_data} XmtState;
+
+struct PRFilePrivate
+{
+ RcvState rcvstate;
+ XmtState xmtstate;
+ PRInt32 rcvreq, rcvinprogress;
+ PRInt32 xmtreq, xmtinprogress;
+};
+
+typedef enum Verbosity {silent, quiet, chatty, noisy} Verbosity;
+
+static PRIntn minor_iterations = 5;
+static PRIntn major_iterations = 1;
+static Verbosity verbosity = quiet;
+
+#ifdef DEBUG
+#define PORT_INC_DO +100
+#else
+#define PORT_INC_DO
+#endif
+#ifdef IS_64
+#define PORT_INC_3264 +200
+#else
+#define PORT_INC_3264
+#endif
+
+static PRUint16 default_port = 12273 PORT_INC_DO PORT_INC_3264;
+
+static PRFileDesc *PushLayer(PRFileDesc *stack)
+{
+ PRStatus rv;
+ PRFileDesc *layer = PR_CreateIOLayerStub(identity, &myMethods);
+ layer->secret = PR_NEWZAP(PRFilePrivate);
+ rv = PR_PushIOLayer(stack, PR_GetLayersIdentity(stack), layer);
+ PR_ASSERT(PR_SUCCESS == rv);
+ if (verbosity > quiet) {
+ PR_fprintf(logFile, "Pushed layer(0x%x) onto stack(0x%x)\n", layer, stack);
+ }
+ return stack;
+} /* PushLayer */
+
+static PRFileDesc *PopLayer(PRFileDesc *stack)
+{
+ PRFileDesc *popped = PR_PopIOLayer(stack, identity);
+ if (verbosity > quiet) {
+ PR_fprintf(logFile, "Popped layer(0x%x) from stack(0x%x)\n", popped, stack);
+ }
+ PR_DELETE(popped->secret);
+ popped->dtor(popped);
+ return stack;
+} /* PopLayer */
+
+static void PR_CALLBACK Client(void *arg)
+{
+ PRStatus rv;
+ PRIntn mits;
+ PRInt32 ready;
+ PRUint8 buffer[100];
+ PRPollDesc polldesc;
+ PRIntn empty_flags = 0;
+ PRIntn bytes_read, bytes_sent;
+ PRFileDesc *stack = (PRFileDesc*)arg;
+
+ /* Initialize the buffer so that Purify won't complain */
+ memset(buffer, 0, sizeof(buffer));
+
+ rv = PR_Connect(stack, &server_address, PR_INTERVAL_NO_TIMEOUT);
+ if ((PR_FAILURE == rv) && (PR_IN_PROGRESS_ERROR == PR_GetError()))
+ {
+ if (verbosity > quiet) {
+ PR_fprintf(logFile, "Client connect 'in progress'\n");
+ }
+ do
+ {
+ polldesc.fd = stack;
+ polldesc.out_flags = 0;
+ polldesc.in_flags = PR_POLL_WRITE | PR_POLL_EXCEPT;
+ ready = PR_Poll(&polldesc, 1, PR_INTERVAL_NO_TIMEOUT);
+ if ((1 != ready) /* if not 1, then we're dead */
+ || (0 == (polldesc.in_flags & polldesc.out_flags)))
+ {
+ PR_NOT_REACHED("Whoa!");
+ break;
+ }
+ if (verbosity > quiet)
+ PR_fprintf(
+ logFile, "Client connect 'in progress' [0x%x]\n",
+ polldesc.out_flags);
+ rv = PR_GetConnectStatus(&polldesc);
+ if ((PR_FAILURE == rv)
+ && (PR_IN_PROGRESS_ERROR != PR_GetError())) {
+ break;
+ }
+ } while (PR_FAILURE == rv);
+ }
+ PR_ASSERT(PR_SUCCESS == rv);
+ if (verbosity > chatty) {
+ PR_fprintf(logFile, "Client created connection\n");
+ }
+
+ for (mits = 0; mits < minor_iterations; ++mits)
+ {
+ bytes_sent = 0;
+ if (verbosity > quiet) {
+ PR_fprintf(logFile, "Client sending %d bytes\n", sizeof(buffer));
+ }
+ do
+ {
+ if (verbosity > chatty)
+ PR_fprintf(
+ logFile, "Client sending %d bytes\n",
+ sizeof(buffer) - bytes_sent);
+ ready = PR_Send(
+ stack, buffer + bytes_sent, sizeof(buffer) - bytes_sent,
+ empty_flags, PR_INTERVAL_NO_TIMEOUT);
+ if (verbosity > chatty) {
+ PR_fprintf(logFile, "Client send status [%d]\n", ready);
+ }
+ if (0 < ready) {
+ bytes_sent += ready;
+ }
+ else if ((-1 == ready) && (PR_WOULD_BLOCK_ERROR == PR_GetError()))
+ {
+ polldesc.fd = stack;
+ polldesc.out_flags = 0;
+ polldesc.in_flags = PR_POLL_WRITE;
+ ready = PR_Poll(&polldesc, 1, PR_INTERVAL_NO_TIMEOUT);
+ if ((1 != ready) /* if not 1, then we're dead */
+ || (0 == (polldesc.in_flags & polldesc.out_flags)))
+ {
+ PR_NOT_REACHED("Whoa!");
+ break;
+ }
+ }
+ else {
+ break;
+ }
+ } while (bytes_sent < sizeof(buffer));
+ PR_ASSERT(sizeof(buffer) == bytes_sent);
+
+ bytes_read = 0;
+ do
+ {
+ if (verbosity > chatty)
+ PR_fprintf(
+ logFile, "Client receiving %d bytes\n",
+ bytes_sent - bytes_read);
+ ready = PR_Recv(
+ stack, buffer + bytes_read, bytes_sent - bytes_read,
+ empty_flags, PR_INTERVAL_NO_TIMEOUT);
+ if (verbosity > chatty)
+ PR_fprintf(
+ logFile, "Client receive status [%d]\n", ready);
+ if (0 < ready) {
+ bytes_read += ready;
+ }
+ else if ((-1 == ready) && (PR_WOULD_BLOCK_ERROR == PR_GetError()))
+ {
+ polldesc.fd = stack;
+ polldesc.out_flags = 0;
+ polldesc.in_flags = PR_POLL_READ;
+ ready = PR_Poll(&polldesc, 1, PR_INTERVAL_NO_TIMEOUT);
+ if ((1 != ready) /* if not 1, then we're dead */
+ || (0 == (polldesc.in_flags & polldesc.out_flags)))
+ {
+ PR_NOT_REACHED("Whoa!");
+ break;
+ }
+ }
+ else {
+ break;
+ }
+ } while (bytes_read < bytes_sent);
+ if (verbosity > chatty) {
+ PR_fprintf(logFile, "Client received %d bytes\n", bytes_read);
+ }
+ PR_ASSERT(bytes_read == bytes_sent);
+ }
+
+ if (verbosity > quiet) {
+ PR_fprintf(logFile, "Client shutting down stack\n");
+ }
+
+ rv = PR_Shutdown(stack, PR_SHUTDOWN_BOTH); PR_ASSERT(PR_SUCCESS == rv);
+} /* Client */
+
+static void PR_CALLBACK Server(void *arg)
+{
+ PRStatus rv;
+ PRInt32 ready;
+ PRUint8 buffer[100];
+ PRFileDesc *service;
+ PRUintn empty_flags = 0;
+ struct PRPollDesc polldesc;
+ PRIntn bytes_read, bytes_sent;
+ PRFileDesc *stack = (PRFileDesc*)arg;
+ PRNetAddr client_address;
+
+ do
+ {
+ if (verbosity > chatty) {
+ PR_fprintf(logFile, "Server accepting connection\n");
+ }
+ service = PR_Accept(stack, &client_address, PR_INTERVAL_NO_TIMEOUT);
+ if (verbosity > chatty) {
+ PR_fprintf(logFile, "Server accept status [0x%p]\n", service);
+ }
+ if ((NULL == service) && (PR_WOULD_BLOCK_ERROR == PR_GetError()))
+ {
+ polldesc.fd = stack;
+ polldesc.out_flags = 0;
+ polldesc.in_flags = PR_POLL_READ | PR_POLL_EXCEPT;
+ ready = PR_Poll(&polldesc, 1, PR_INTERVAL_NO_TIMEOUT);
+ if ((1 != ready) /* if not 1, then we're dead */
+ || (0 == (polldesc.in_flags & polldesc.out_flags)))
+ {
+ PR_NOT_REACHED("Whoa!");
+ break;
+ }
+ }
+ } while (NULL == service);
+ PR_ASSERT(NULL != service);
+
+ if (verbosity > quiet) {
+ PR_fprintf(logFile, "Server accepting connection\n");
+ }
+
+ do
+ {
+ bytes_read = 0;
+ do
+ {
+ if (verbosity > chatty)
+ PR_fprintf(
+ logFile, "Server receiving %d bytes\n",
+ sizeof(buffer) - bytes_read);
+ ready = PR_Recv(
+ service, buffer + bytes_read, sizeof(buffer) - bytes_read,
+ empty_flags, PR_INTERVAL_NO_TIMEOUT);
+ if (verbosity > chatty) {
+ PR_fprintf(logFile, "Server receive status [%d]\n", ready);
+ }
+ if (0 < ready) {
+ bytes_read += ready;
+ }
+ else if ((-1 == ready) && (PR_WOULD_BLOCK_ERROR == PR_GetError()))
+ {
+ polldesc.fd = service;
+ polldesc.out_flags = 0;
+ polldesc.in_flags = PR_POLL_READ;
+ ready = PR_Poll(&polldesc, 1, PR_INTERVAL_NO_TIMEOUT);
+ if ((1 != ready) /* if not 1, then we're dead */
+ || (0 == (polldesc.in_flags & polldesc.out_flags)))
+ {
+ PR_NOT_REACHED("Whoa!");
+ break;
+ }
+ }
+ else {
+ break;
+ }
+ } while (bytes_read < sizeof(buffer));
+
+ if (0 != bytes_read)
+ {
+ if (verbosity > chatty) {
+ PR_fprintf(logFile, "Server received %d bytes\n", bytes_read);
+ }
+ PR_ASSERT(bytes_read > 0);
+
+ bytes_sent = 0;
+ do
+ {
+ ready = PR_Send(
+ service, buffer + bytes_sent, bytes_read - bytes_sent,
+ empty_flags, PR_INTERVAL_NO_TIMEOUT);
+ if (0 < ready)
+ {
+ bytes_sent += ready;
+ }
+ else if ((-1 == ready) && (PR_WOULD_BLOCK_ERROR == PR_GetError()))
+ {
+ polldesc.fd = service;
+ polldesc.out_flags = 0;
+ polldesc.in_flags = PR_POLL_WRITE;
+ ready = PR_Poll(&polldesc, 1, PR_INTERVAL_NO_TIMEOUT);
+ if ((1 != ready) /* if not 1, then we're dead */
+ || (0 == (polldesc.in_flags & polldesc.out_flags)))
+ {
+ PR_NOT_REACHED("Whoa!");
+ break;
+ }
+ }
+ else {
+ break;
+ }
+ } while (bytes_sent < bytes_read);
+ PR_ASSERT(bytes_read == bytes_sent);
+ if (verbosity > chatty) {
+ PR_fprintf(logFile, "Server sent %d bytes\n", bytes_sent);
+ }
+ }
+ } while (0 != bytes_read);
+
+ if (verbosity > quiet) {
+ PR_fprintf(logFile, "Server shutting down stack\n");
+ }
+ rv = PR_Shutdown(service, PR_SHUTDOWN_BOTH); PR_ASSERT(PR_SUCCESS == rv);
+ rv = PR_Close(service); PR_ASSERT(PR_SUCCESS == rv);
+
+} /* Server */
+
+static PRStatus PR_CALLBACK MyClose(PRFileDesc *fd)
+{
+ PR_DELETE(fd->secret); /* manage my secret file object */
+ return (PR_GetDefaultIOMethods())->close(fd); /* let him do all the work */
+} /* MyClose */
+
+static PRInt16 PR_CALLBACK MyPoll(
+ PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags)
+{
+ PRInt16 my_flags, new_flags;
+ PRFilePrivate *mine = (PRFilePrivate*)fd->secret;
+ if (0 != (PR_POLL_READ & in_flags))
+ {
+ /* client thinks he's reading */
+ switch (mine->rcvstate)
+ {
+ case rcv_send_credit:
+ my_flags = (in_flags & ~PR_POLL_READ) | PR_POLL_WRITE;
+ break;
+ case rcv_data:
+ case rcv_get_debit:
+ my_flags = in_flags;
+ default: break;
+ }
+ }
+ else if (0 != (PR_POLL_WRITE & in_flags))
+ {
+ /* client thinks he's writing */
+ switch (mine->xmtstate)
+ {
+ case xmt_recv_credit:
+ my_flags = (in_flags & ~PR_POLL_WRITE) | PR_POLL_READ;
+ break;
+ case xmt_send_debit:
+ case xmt_data:
+ my_flags = in_flags;
+ default: break;
+ }
+ }
+ else {
+ PR_NOT_REACHED("How'd I get here?");
+ }
+ new_flags = (fd->lower->methods->poll)(fd->lower, my_flags, out_flags);
+ if (verbosity > chatty)
+ PR_fprintf(
+ logFile, "Poll [i: 0x%x, m: 0x%x, o: 0x%x, n: 0x%x]\n",
+ in_flags, my_flags, *out_flags, new_flags);
+ return new_flags;
+} /* MyPoll */
+
+static PRFileDesc * PR_CALLBACK MyAccept(
+ PRFileDesc *fd, PRNetAddr *addr, PRIntervalTime timeout)
+{
+ PRStatus rv;
+ PRFileDesc *newfd, *layer = fd;
+ PRFileDesc *newstack;
+ PRFilePrivate *newsecret;
+
+ PR_ASSERT(fd != NULL);
+ PR_ASSERT(fd->lower != NULL);
+
+ newstack = PR_NEW(PRFileDesc);
+ if (NULL == newstack)
+ {
+ PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+ return NULL;
+ }
+ newsecret = PR_NEW(PRFilePrivate);
+ if (NULL == newsecret)
+ {
+ PR_DELETE(newstack);
+ PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+ return NULL;
+ }
+ *newstack = *fd; /* make a copy of the accepting layer */
+ *newsecret = *fd->secret;
+ newstack->secret = newsecret;
+
+ newfd = (fd->lower->methods->accept)(fd->lower, addr, timeout);
+ if (NULL == newfd)
+ {
+ PR_DELETE(newsecret);
+ PR_DELETE(newstack);
+ return NULL;
+ }
+
+ /* this PR_PushIOLayer call cannot fail */
+ rv = PR_PushIOLayer(newfd, PR_TOP_IO_LAYER, newstack);
+ PR_ASSERT(PR_SUCCESS == rv);
+ return newfd; /* that's it */
+}
+
+static PRInt32 PR_CALLBACK MyRecv(
+ PRFileDesc *fd, void *buf, PRInt32 amount,
+ PRIntn flags, PRIntervalTime timeout)
+{
+ char *b;
+ PRInt32 rv;
+ PRFileDesc *lo = fd->lower;
+ PRFilePrivate *mine = (PRFilePrivate*)fd->secret;
+
+ do
+ {
+ switch (mine->rcvstate)
+ {
+ case rcv_get_debit:
+ b = (char*)&mine->rcvreq;
+ mine->rcvreq = amount;
+ rv = lo->methods->recv(
+ lo, b + mine->rcvinprogress,
+ sizeof(mine->rcvreq) - mine->rcvinprogress, flags, timeout);
+ if (0 == rv) {
+ goto closed;
+ }
+ if ((-1 == rv) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) {
+ break;
+ }
+ mine->rcvinprogress += rv; /* accumulate the read */
+ if (mine->rcvinprogress < sizeof(mine->rcvreq)) {
+ break; /* loop */
+ }
+ mine->rcvstate = rcv_send_credit;
+ mine->rcvinprogress = 0;
+ case rcv_send_credit:
+ b = (char*)&mine->rcvreq;
+ rv = lo->methods->send(
+ lo, b + mine->rcvinprogress,
+ sizeof(mine->rcvreq) - mine->rcvinprogress, flags, timeout);
+ if ((-1 == rv) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) {
+ break;
+ }
+ mine->rcvinprogress += rv; /* accumulate the read */
+ if (mine->rcvinprogress < sizeof(mine->rcvreq)) {
+ break; /* loop */
+ }
+ mine->rcvstate = rcv_data;
+ mine->rcvinprogress = 0;
+ case rcv_data:
+ b = (char*)buf;
+ rv = lo->methods->recv(
+ lo, b + mine->rcvinprogress,
+ mine->rcvreq - mine->rcvinprogress, flags, timeout);
+ if (0 == rv) {
+ goto closed;
+ }
+ if ((-1 == rv) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) {
+ break;
+ }
+ mine->rcvinprogress += rv; /* accumulate the read */
+ if (mine->rcvinprogress < amount) {
+ break; /* loop */
+ }
+ mine->rcvstate = rcv_get_debit;
+ mine->rcvinprogress = 0;
+ return mine->rcvreq; /* << -- that's it! */
+ default:
+ break;
+ }
+ } while (-1 != rv);
+ return rv;
+closed:
+ mine->rcvinprogress = 0;
+ mine->rcvstate = rcv_get_debit;
+ return 0;
+} /* MyRecv */
+
+static PRInt32 PR_CALLBACK MySend(
+ PRFileDesc *fd, const void *buf, PRInt32 amount,
+ PRIntn flags, PRIntervalTime timeout)
+{
+ char *b;
+ PRInt32 rv;
+ PRFileDesc *lo = fd->lower;
+ PRFilePrivate *mine = (PRFilePrivate*)fd->secret;
+
+ do
+ {
+ switch (mine->xmtstate)
+ {
+ case xmt_send_debit:
+ b = (char*)&mine->xmtreq;
+ mine->xmtreq = amount;
+ rv = lo->methods->send(
+ lo, b - mine->xmtinprogress,
+ sizeof(mine->xmtreq) - mine->xmtinprogress, flags, timeout);
+ if ((-1 == rv) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) {
+ break;
+ }
+ mine->xmtinprogress += rv;
+ if (mine->xmtinprogress < sizeof(mine->xmtreq)) {
+ break;
+ }
+ mine->xmtstate = xmt_recv_credit;
+ mine->xmtinprogress = 0;
+ case xmt_recv_credit:
+ b = (char*)&mine->xmtreq;
+ rv = lo->methods->recv(
+ lo, b + mine->xmtinprogress,
+ sizeof(mine->xmtreq) - mine->xmtinprogress, flags, timeout);
+ if ((-1 == rv) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) {
+ break;
+ }
+ mine->xmtinprogress += rv;
+ if (mine->xmtinprogress < sizeof(mine->xmtreq)) {
+ break;
+ }
+ mine->xmtstate = xmt_data;
+ mine->xmtinprogress = 0;
+ case xmt_data:
+ b = (char*)buf;
+ rv = lo->methods->send(
+ lo, b + mine->xmtinprogress,
+ mine->xmtreq - mine->xmtinprogress, flags, timeout);
+ if ((-1 == rv) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) {
+ break;
+ }
+ mine->xmtinprogress += rv;
+ if (mine->xmtinprogress < amount) {
+ break;
+ }
+ mine->xmtstate = xmt_send_debit;
+ mine->xmtinprogress = 0;
+ return mine->xmtreq; /* <<-- That's the one! */
+ default:
+ break;
+ }
+ } while (-1 != rv);
+ return rv;
+} /* MySend */
+
+static Verbosity ChangeVerbosity(Verbosity verbosity, PRIntn delta)
+{
+ PRIntn verbage = (PRIntn)verbosity + delta;
+ if (verbage < (PRIntn)silent) {
+ verbage = (PRIntn)silent;
+ }
+ else if (verbage > (PRIntn)noisy) {
+ verbage = (PRIntn)noisy;
+ }
+ return (Verbosity)verbage;
+} /* ChangeVerbosity */
+
+int main(int argc, char **argv)
+{
+ PRStatus rv;
+ PLOptStatus os;
+ PRFileDesc *client, *service;
+ PRNetAddr any_address;
+ const char *server_name = NULL;
+ const PRIOMethods *stubMethods;
+ PRThread *client_thread, *server_thread;
+ PRThreadScope thread_scope = PR_LOCAL_THREAD;
+ PRSocketOptionData socket_noblock, socket_nodelay;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "dqGC:c:p:");
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 0:
+ server_name = opt->value;
+ break;
+ case 'd': /* debug mode */
+ if (verbosity < noisy) {
+ verbosity = ChangeVerbosity(verbosity, 1);
+ }
+ break;
+ case 'q': /* debug mode */
+ if (verbosity > silent) {
+ verbosity = ChangeVerbosity(verbosity, -1);
+ }
+ break;
+ case 'G': /* use global threads */
+ thread_scope = PR_GLOBAL_THREAD;
+ break;
+ case 'C': /* number of threads waiting */
+ major_iterations = atoi(opt->value);
+ break;
+ case 'c': /* number of client threads */
+ minor_iterations = atoi(opt->value);
+ break;
+ case 'p': /* default port */
+ default_port = atoi(opt->value);
+ break;
+ default:
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+ PR_STDIO_INIT();
+
+ logFile = PR_GetSpecialFD(PR_StandardError);
+ identity = PR_GetUniqueIdentity("Dummy");
+ stubMethods = PR_GetDefaultIOMethods();
+
+ /*
+ ** The protocol we're going to implement is one where in order to initiate
+ ** a send, the sender must first solicit permission. Therefore, every
+ ** send is really a send - receive - send sequence.
+ */
+ myMethods = *stubMethods; /* first get the entire batch */
+ myMethods.accept = MyAccept; /* then override the ones we care about */
+ myMethods.recv = MyRecv; /* then override the ones we care about */
+ myMethods.send = MySend; /* then override the ones we care about */
+ myMethods.close = MyClose; /* then override the ones we care about */
+ myMethods.poll = MyPoll; /* then override the ones we care about */
+
+ if (NULL == server_name)
+ rv = PR_InitializeNetAddr(
+ PR_IpAddrLoopback, default_port, &server_address);
+ else
+ {
+ rv = PR_StringToNetAddr(server_name, &server_address);
+ PR_ASSERT(PR_SUCCESS == rv);
+ rv = PR_InitializeNetAddr(
+ PR_IpAddrNull, default_port, &server_address);
+ }
+ PR_ASSERT(PR_SUCCESS == rv);
+
+ socket_noblock.value.non_blocking = PR_TRUE;
+ socket_noblock.option = PR_SockOpt_Nonblocking;
+ socket_nodelay.value.no_delay = PR_TRUE;
+ socket_nodelay.option = PR_SockOpt_NoDelay;
+
+ /* one type w/o layering */
+
+ while (major_iterations-- > 0)
+ {
+ if (verbosity > silent) {
+ PR_fprintf(logFile, "Beginning non-layered test\n");
+ }
+
+ client = PR_NewTCPSocket(); PR_ASSERT(NULL != client);
+ service = PR_NewTCPSocket(); PR_ASSERT(NULL != service);
+
+ rv = PR_SetSocketOption(client, &socket_noblock);
+ PR_ASSERT(PR_SUCCESS == rv);
+ rv = PR_SetSocketOption(service, &socket_noblock);
+ PR_ASSERT(PR_SUCCESS == rv);
+ rv = PR_SetSocketOption(client, &socket_nodelay);
+ PR_ASSERT(PR_SUCCESS == rv);
+ rv = PR_SetSocketOption(service, &socket_nodelay);
+ PR_ASSERT(PR_SUCCESS == rv);
+
+ rv = PR_InitializeNetAddr(PR_IpAddrAny, default_port, &any_address);
+ PR_ASSERT(PR_SUCCESS == rv);
+ rv = PR_Bind(service, &any_address); PR_ASSERT(PR_SUCCESS == rv);
+ rv = PR_Listen(service, 10); PR_ASSERT(PR_SUCCESS == rv);
+
+ server_thread = PR_CreateThread(
+ PR_USER_THREAD, Server, service,
+ PR_PRIORITY_HIGH, thread_scope,
+ PR_JOINABLE_THREAD, 16 * 1024);
+ PR_ASSERT(NULL != server_thread);
+
+ client_thread = PR_CreateThread(
+ PR_USER_THREAD, Client, client,
+ PR_PRIORITY_NORMAL, thread_scope,
+ PR_JOINABLE_THREAD, 16 * 1024);
+ PR_ASSERT(NULL != client_thread);
+
+ rv = PR_JoinThread(client_thread);
+ PR_ASSERT(PR_SUCCESS == rv);
+ rv = PR_JoinThread(server_thread);
+ PR_ASSERT(PR_SUCCESS == rv);
+
+ rv = PR_Close(client); PR_ASSERT(PR_SUCCESS == rv);
+ rv = PR_Close(service); PR_ASSERT(PR_SUCCESS == rv);
+ if (verbosity > silent) {
+ PR_fprintf(logFile, "Ending non-layered test\n");
+ }
+
+ /* with layering */
+ if (verbosity > silent) {
+ PR_fprintf(logFile, "Beginning layered test\n");
+ }
+ client = PR_NewTCPSocket(); PR_ASSERT(NULL != client);
+ service = PR_NewTCPSocket(); PR_ASSERT(NULL != service);
+
+ rv = PR_SetSocketOption(client, &socket_noblock);
+ PR_ASSERT(PR_SUCCESS == rv);
+ rv = PR_SetSocketOption(service, &socket_noblock);
+ PR_ASSERT(PR_SUCCESS == rv);
+ rv = PR_SetSocketOption(client, &socket_nodelay);
+ PR_ASSERT(PR_SUCCESS == rv);
+ rv = PR_SetSocketOption(service, &socket_nodelay);
+ PR_ASSERT(PR_SUCCESS == rv);
+
+ PushLayer(client);
+ PushLayer(service);
+
+ rv = PR_InitializeNetAddr(PR_IpAddrAny, default_port, &any_address);
+ PR_ASSERT(PR_SUCCESS == rv);
+ rv = PR_Bind(service, &any_address); PR_ASSERT(PR_SUCCESS == rv);
+ rv = PR_Listen(service, 10); PR_ASSERT(PR_SUCCESS == rv);
+
+ server_thread = PR_CreateThread(
+ PR_USER_THREAD, Server, service,
+ PR_PRIORITY_HIGH, thread_scope,
+ PR_JOINABLE_THREAD, 16 * 1024);
+ PR_ASSERT(NULL != server_thread);
+
+ client_thread = PR_CreateThread(
+ PR_USER_THREAD, Client, client,
+ PR_PRIORITY_NORMAL, thread_scope,
+ PR_JOINABLE_THREAD, 16 * 1024);
+ PR_ASSERT(NULL != client_thread);
+
+ rv = PR_JoinThread(client_thread);
+ PR_ASSERT(PR_SUCCESS == rv);
+ rv = PR_JoinThread(server_thread);
+ PR_ASSERT(PR_SUCCESS == rv);
+
+ rv = PR_Close(PopLayer(client)); PR_ASSERT(PR_SUCCESS == rv);
+ rv = PR_Close(PopLayer(service)); PR_ASSERT(PR_SUCCESS == rv);
+ if (verbosity > silent) {
+ PR_fprintf(logFile, "Ending layered test\n");
+ }
+ }
+ return 0;
+} /* main */
+
+/* nblayer.c */
diff --git a/nsprpub/pr/tests/nonblock.c b/nsprpub/pr/tests/nonblock.c
new file mode 100644
index 0000000000..f24ffb02d0
--- /dev/null
+++ b/nsprpub/pr/tests/nonblock.c
@@ -0,0 +1,223 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nspr.h"
+#include "prio.h"
+#include "prerror.h"
+#include "prlog.h"
+#include "prprf.h"
+#include "prnetdb.h"
+#include "plerror.h"
+#include "obsolete/probslet.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#define NUMBER_ROUNDS 5
+
+#if defined(WIN16)
+/*
+** Make win16 unit_time interval 300 milliseconds, others get 100
+*/
+#define UNIT_TIME 200 /* unit time in milliseconds */
+#else
+#define UNIT_TIME 100 /* unit time in milliseconds */
+#endif
+#define CHUNK_SIZE 10
+#undef USE_PR_SELECT /* If defined, we use PR_Select.
+ * If not defined, use PR_Poll instead. */
+
+#if defined(USE_PR_SELECT)
+#include "pprio.h"
+#endif
+
+static void PR_CALLBACK
+clientThreadFunc(void *arg)
+{
+ PRUintn port = (PRUintn)arg;
+ PRFileDesc *sock;
+ PRNetAddr addr;
+ char buf[CHUNK_SIZE];
+ int i;
+ PRIntervalTime unitTime = PR_MillisecondsToInterval(UNIT_TIME);
+ PRSocketOptionData optval;
+ PRStatus retVal;
+ PRInt32 nBytes;
+
+ /* Initialize the buffer so that Purify won't complain */
+ memset(buf, 0, sizeof(buf));
+
+ addr.inet.family = PR_AF_INET;
+ addr.inet.port = PR_htons((PRUint16)port);
+ addr.inet.ip = PR_htonl(PR_INADDR_LOOPBACK);
+ PR_snprintf(buf, sizeof(buf), "%hu", addr.inet.ip);
+
+ /* time 1 */
+ PR_Sleep(unitTime);
+ sock = PR_NewTCPSocket();
+ optval.option = PR_SockOpt_Nonblocking;
+ optval.value.non_blocking = PR_TRUE;
+ PR_SetSocketOption(sock, &optval);
+ retVal = PR_Connect(sock, &addr, PR_INTERVAL_NO_TIMEOUT);
+ if (retVal == PR_FAILURE && PR_GetError() == PR_IN_PROGRESS_ERROR) {
+#if !defined(USE_PR_SELECT)
+ PRPollDesc pd;
+ PRInt32 n;
+ fprintf(stderr, "connect: EWOULDBLOCK, good\n");
+ pd.fd = sock;
+ pd.in_flags = PR_POLL_WRITE;
+ n = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT);
+ PR_ASSERT(n == 1);
+ PR_ASSERT(pd.out_flags == PR_POLL_WRITE);
+#else
+ PR_fd_set writeSet;
+ PRInt32 n;
+ fprintf(stderr, "connect: EWOULDBLOCK, good\n");
+ PR_FD_ZERO(&writeSet);
+ PR_FD_SET(sock, &writeSet);
+ n = PR_Select(0, NULL, &writeSet, NULL, PR_INTERVAL_NO_TIMEOUT);
+ PR_ASSERT(n == 1);
+ PR_ASSERT(PR_FD_ISSET(sock, &writeSet));
+#endif
+ }
+ printf("client connected\n");
+ fflush(stdout);
+
+ /* time 4, 7, 11, etc. */
+ for (i = 0; i < NUMBER_ROUNDS; i++) {
+ PR_Sleep(3 * unitTime);
+ nBytes = PR_Write(sock, buf, sizeof(buf));
+ if (nBytes == -1) {
+ if (PR_GetError() == PR_WOULD_BLOCK_ERROR) {
+ fprintf(stderr, "write: EWOULDBLOCK\n");
+ exit(1);
+ } else {
+ fprintf(stderr, "write: failed\n");
+ }
+ }
+ printf("client sent %d bytes\n", nBytes);
+ fflush(stdout);
+ }
+
+ PR_Close(sock);
+}
+
+static PRIntn PR_CALLBACK RealMain( PRIntn argc, char **argv )
+{
+ PRFileDesc *listenSock, *sock;
+ PRUint16 listenPort;
+ PRNetAddr addr;
+ char buf[CHUNK_SIZE];
+ PRThread *clientThread;
+ PRInt32 retVal;
+ PRSocketOptionData optval;
+ PRIntn i;
+ PRIntervalTime unitTime = PR_MillisecondsToInterval(UNIT_TIME);
+
+ /* Create a listening socket */
+ if ((listenSock = PR_NewTCPSocket()) == NULL) {
+ fprintf(stderr, "Can't create a new TCP socket\n");
+ exit(1);
+ }
+ addr.inet.family = PR_AF_INET;
+ addr.inet.ip = PR_htonl(PR_INADDR_ANY);
+ addr.inet.port = PR_htons(0);
+ if (PR_Bind(listenSock, &addr) == PR_FAILURE) {
+ fprintf(stderr, "Can't bind socket\n");
+ exit(1);
+ }
+ if (PR_GetSockName(listenSock, &addr) == PR_FAILURE) {
+ fprintf(stderr, "PR_GetSockName failed\n");
+ exit(1);
+ }
+ listenPort = PR_ntohs(addr.inet.port);
+ if (PR_Listen(listenSock, 5) == PR_FAILURE) {
+ fprintf(stderr, "Can't listen on a socket\n");
+ exit(1);
+ }
+
+ PR_snprintf(buf, sizeof(buf),
+ "The server thread is listening on port %hu\n\n",
+ listenPort);
+ printf("%s", buf);
+
+ clientThread = PR_CreateThread(PR_USER_THREAD,
+ clientThreadFunc, (void *) listenPort,
+ PR_PRIORITY_NORMAL, PR_LOCAL_THREAD,
+ PR_UNJOINABLE_THREAD, 0);
+ if (clientThread == NULL) {
+ fprintf(stderr, "can't create thread\n");
+ exit(1);
+ }
+
+ printf("client thread created.\n");
+
+ optval.option = PR_SockOpt_Nonblocking;
+ optval.value.non_blocking = PR_TRUE;
+ PR_SetSocketOption(listenSock, &optval);
+ /* time 0 */
+ sock = PR_Accept(listenSock, NULL, PR_INTERVAL_NO_TIMEOUT);
+ if (sock != NULL || PR_GetError() != PR_WOULD_BLOCK_ERROR) {
+ PL_PrintError("First Accept\n");
+ fprintf(stderr, "First PR_Accept() xxx\n" );
+ exit(1);
+ }
+ printf("accept: EWOULDBLOCK, good\n");
+ fflush(stdout);
+ /* time 2 */
+ PR_Sleep(2 * unitTime);
+ sock = PR_Accept(listenSock, NULL, PR_INTERVAL_NO_TIMEOUT);
+ if (sock == NULL) {
+ PL_PrintError("Second Accept\n");
+ fprintf(stderr, "Second PR_Accept() failed: (%d, %d)\n",
+ PR_GetError(), PR_GetOSError());
+ exit(1);
+ }
+ printf("accept: succeeded, good\n");
+ fflush(stdout);
+ PR_Close(listenSock);
+
+ PR_SetSocketOption(sock, &optval);
+
+ /* time 3, 5, 6, 8, etc. */
+ for (i = 0; i < NUMBER_ROUNDS; i++) {
+ PR_Sleep(unitTime);
+ retVal = PR_Recv(sock, buf, sizeof(buf), 0, PR_INTERVAL_NO_TIMEOUT);
+ if (retVal != -1 || PR_GetError() != PR_WOULD_BLOCK_ERROR) {
+ PL_PrintError("First Receive:\n");
+ fprintf(stderr, "First PR_Recv: retVal: %ld, Error: %ld\n",
+ retVal, PR_GetError());
+ exit(1);
+ }
+ printf("read: EWOULDBLOCK, good\n");
+ fflush(stdout);
+ PR_Sleep(2 * unitTime);
+ retVal = PR_Recv(sock, buf, sizeof(buf), 0, PR_INTERVAL_NO_TIMEOUT);
+ if (retVal != CHUNK_SIZE) {
+ PL_PrintError("Second Receive:\n");
+ fprintf(stderr, "Second PR_Recv: retVal: %ld, Error: %ld\n",
+ retVal, PR_GetError());
+ exit(1);
+ }
+ printf("read: %d bytes, good\n", retVal);
+ fflush(stdout);
+ }
+ PR_Close(sock);
+
+ printf("All tests finished\n");
+ printf("PASS\n");
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ PRIntn rv;
+
+ PR_STDIO_INIT();
+ rv = PR_Initialize(RealMain, argc, argv, 0);
+ return rv;
+} /* main */
+
diff --git a/nsprpub/pr/tests/ntioto.c b/nsprpub/pr/tests/ntioto.c
new file mode 100644
index 0000000000..809e0ae5c6
--- /dev/null
+++ b/nsprpub/pr/tests/ntioto.c
@@ -0,0 +1,319 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+** File: ntioto.c
+** Description:
+** This test, ntioto.c, was designed to reproduce a bug reported by NES
+** on WindowsNT (fibers implementation). NSPR was asserting in ntio.c
+** after PR_AcceptRead() had timed out. I/O performed subsequent to the
+** call to PR_AcceptRead() could complete on a CPU other than the one
+** on which it was started. The assert in ntio.c detected this, then
+** asserted.
+**
+** Design:
+** This test will fail with an assert in ntio.c if the problem it was
+** designed to catch occurs. It returns 0 otherwise.
+**
+** The main() thread initializes and tears things down. A file is
+** opened for writing; this file will be written to by AcceptThread()
+** and JitterThread(). Main() creates a socket for reading, listens
+** and binds the socket.
+**
+** ConnectThread() connects to the socket created by main, then polls
+** the "state" variable. When state is AllDone, ConnectThread() exits.
+**
+** AcceptThread() calls PR_AcceptRead() on the socket. He fully expects
+** it to time out. After the timeout, AccpetThread() interacts with
+** JitterThread() via a common condition variable and the state
+** variable. The two threads ping-pong back and forth, each thread
+** writes the the file opened by main. This should provoke the
+** condition reported by NES (if we didn't fix it).
+**
+** The failure is not solid. It may fail within a few ping-pongs between
+** AcceptThread() and JitterThread() or may take a while. The default
+** iteration count, jitter, is set by DEFAULT_JITTER. This may be
+** modified at the command line with the -j option.
+**
+*/
+
+#include <plgetopt.h>
+#include <nspr.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+** Test harness infrastructure
+*/
+PRLogModuleInfo *lm;
+PRLogModuleLevel msgLevel = PR_LOG_NONE;
+PRIntn debug = 0;
+PRIntn verbose = 0;
+PRUint32 failed_already = 0;
+/* end Test harness infrastructure */
+
+/* JITTER_DEFAULT: the number of times AcceptThread() and JitterThread() ping-pong */
+#define JITTER_DEFAULT 100000
+
+#ifdef DEBUG
+#define PORT_INC_DO +100
+#else
+#define PORT_INC_DO
+#endif
+#ifdef IS_64
+#define PORT_INC_3264 +200
+#else
+#define PORT_INC_3264
+#endif
+
+#define BASE_PORT 9867 PORT_INC_DO PORT_INC_3264
+
+PRIntervalTime timeout;
+PRNetAddr listenAddr;
+PRFileDesc *listenSock;
+PRLock *ml;
+PRCondVar *cv;
+volatile enum {
+ RunJitter,
+ RunAcceptRead,
+ AllDone
+} state = RunAcceptRead;
+PRFileDesc *file1;
+PRIntn iCounter = 0;
+PRIntn jitter = JITTER_DEFAULT;
+PRBool resume = PR_FALSE;
+
+/*
+** Emit help text for this test
+*/
+static void Help( void )
+{
+ printf("Template: Help(): display your help message(s) here");
+ exit(1);
+} /* end Help() */
+
+
+/*
+** static computation of PR_AcceptRead() buffer size.
+*/
+#define ACCEPT_READ_DATASIZE 10
+#define ACCEPT_READ_BUFSIZE (PR_ACCEPT_READ_BUF_OVERHEAD + ACCEPT_READ_DATASIZE)
+
+static void AcceptThread(void *arg)
+{
+ PRIntn bytesRead;
+ char dataBuf[ACCEPT_READ_BUFSIZE];
+ PRFileDesc *arSock;
+ PRNetAddr *arAddr;
+
+ bytesRead = PR_AcceptRead( listenSock,
+ &arSock,
+ &arAddr,
+ dataBuf,
+ ACCEPT_READ_DATASIZE,
+ PR_SecondsToInterval(1));
+
+ if ( bytesRead == -1 && PR_GetError() == PR_IO_TIMEOUT_ERROR ) {
+ if ( debug ) {
+ printf("AcceptRead timed out\n");
+ }
+ } else {
+ if ( debug ) {
+ printf("Oops! read: %d, error: %d\n", bytesRead, PR_GetError());
+ }
+ }
+
+ while( state != AllDone ) {
+ PR_Lock( ml );
+ while( state != RunAcceptRead ) {
+ PR_WaitCondVar( cv, PR_INTERVAL_NO_TIMEOUT );
+ }
+ if ( ++iCounter >= jitter ) {
+ state = AllDone;
+ }
+ else {
+ state = RunJitter;
+ }
+ if ( verbose ) {
+ printf(".");
+ }
+ PR_NotifyCondVar( cv );
+ PR_Unlock( ml );
+ PR_Write( file1, ".", 1 );
+ }
+
+ return;
+} /* end AcceptThread() */
+
+static void JitterThread(void *arg)
+{
+ while( state != AllDone ) {
+ PR_Lock( ml );
+ while( state != RunJitter && state != AllDone ) {
+ PR_WaitCondVar( cv, PR_INTERVAL_NO_TIMEOUT );
+ }
+ if ( state != AllDone) {
+ state = RunAcceptRead;
+ }
+ if ( verbose ) {
+ printf("+");
+ }
+ PR_NotifyCondVar( cv );
+ PR_Unlock( ml );
+ PR_Write( file1, "+", 1 );
+ }
+ return;
+} /* end Goofy() */
+
+static void ConnectThread( void *arg )
+{
+ PRStatus rv;
+ PRFileDesc *clientSock;
+ PRNetAddr serverAddress;
+ clientSock = PR_NewTCPSocket();
+
+ PR_ASSERT(clientSock);
+
+ if ( resume ) {
+ if ( debug ) {
+ printf("pausing 3 seconds before connect\n");
+ }
+ PR_Sleep( PR_SecondsToInterval(3));
+ }
+
+ memset(&serverAddress, 0, sizeof(serverAddress));
+ rv = PR_InitializeNetAddr(PR_IpAddrLoopback, BASE_PORT, &serverAddress);
+ PR_ASSERT( PR_SUCCESS == rv );
+ rv = PR_Connect( clientSock,
+ &serverAddress,
+ PR_SecondsToInterval(1));
+ PR_ASSERT( PR_SUCCESS == rv );
+
+ /* that's all we do. ... Wait for the acceptread() to timeout */
+ while( state != AllDone ) {
+ PR_Sleep( PR_SecondsToInterval(1));
+ }
+ return;
+} /* end ConnectThread() */
+
+
+int main(int argc, char **argv)
+{
+ PRThread *tJitter;
+ PRThread *tAccept;
+ PRThread *tConnect;
+ PRStatus rv;
+ /* This test if valid for WinNT only! */
+
+#if !defined(WINNT)
+ return 0;
+#endif
+
+ {
+ /*
+ ** Get command line options
+ */
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "hdrvj:");
+
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 'd': /* debug */
+ debug = 1;
+ msgLevel = PR_LOG_ERROR;
+ break;
+ case 'v': /* verbose mode */
+ verbose = 1;
+ msgLevel = PR_LOG_DEBUG;
+ break;
+ case 'j':
+ jitter = atoi(opt->value);
+ if ( jitter == 0) {
+ jitter = JITTER_DEFAULT;
+ }
+ break;
+ case 'r':
+ resume = PR_TRUE;
+ break;
+ case 'h': /* help message */
+ Help();
+ break;
+ default:
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+ }
+
+ lm = PR_NewLogModule("Test"); /* Initialize logging */
+
+ /* set concurrency */
+ PR_SetConcurrency( 4 );
+
+ /* setup thread synchronization mechanics */
+ ml = PR_NewLock();
+ cv = PR_NewCondVar( ml );
+
+ /* setup a tcp socket */
+ memset(&listenAddr, 0, sizeof(listenAddr));
+ rv = PR_InitializeNetAddr(PR_IpAddrAny, BASE_PORT, &listenAddr);
+ PR_ASSERT( PR_SUCCESS == rv );
+
+ listenSock = PR_NewTCPSocket();
+ PR_ASSERT( listenSock );
+
+ rv = PR_Bind( listenSock, &listenAddr);
+ PR_ASSERT( PR_SUCCESS == rv );
+
+ rv = PR_Listen( listenSock, 5 );
+ PR_ASSERT( PR_SUCCESS == rv );
+
+ /* open a file for writing, provoke bug */
+ file1 = PR_Open("xxxTestFile", PR_CREATE_FILE | PR_RDWR, 666);
+
+ /* create Connect thread */
+ tConnect = PR_CreateThread(
+ PR_USER_THREAD, ConnectThread, NULL,
+ PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
+ PR_JOINABLE_THREAD, 0 );
+ PR_ASSERT( tConnect );
+
+ /* create jitter off thread */
+ tJitter = PR_CreateThread(
+ PR_USER_THREAD, JitterThread, NULL,
+ PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
+ PR_JOINABLE_THREAD, 0 );
+ PR_ASSERT( tJitter );
+
+ /* create acceptread thread */
+ tAccept = PR_CreateThread(
+ PR_USER_THREAD, AcceptThread, NULL,
+ PR_PRIORITY_NORMAL, PR_LOCAL_THREAD,
+ PR_JOINABLE_THREAD, 0 );
+ PR_ASSERT( tAccept );
+
+ /* wait for all threads to quit, then terminate gracefully */
+ PR_JoinThread( tConnect );
+ PR_JoinThread( tAccept );
+ PR_JoinThread( tJitter );
+ PR_Close( listenSock );
+ PR_DestroyCondVar(cv);
+ PR_DestroyLock(ml);
+ PR_Close( file1 );
+ PR_Delete( "xxxTestFile");
+
+ /* test return and exit */
+ if (debug) {
+ printf("%s\n", (failed_already)? "FAIL" : "PASS");
+ }
+ return( (failed_already == PR_TRUE )? 1 : 0 );
+} /* main() */
+/* end ntioto.c */
diff --git a/nsprpub/pr/tests/ntoh.c b/nsprpub/pr/tests/ntoh.c
new file mode 100644
index 0000000000..980a1b4983
--- /dev/null
+++ b/nsprpub/pr/tests/ntoh.c
@@ -0,0 +1,93 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * A test program for PR_htons, PR_ntohs, PR_htonl, PR_ntohl,
+ * PR_htonll, and PR_ntohll.
+ */
+
+#include "prnetdb.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+/* Byte sequence in network byte order */
+static unsigned char bytes_n[8] = { 1, 2, 3, 4, 5, 6, 7, 8 };
+
+/* Integers in host byte order */
+static PRUint16 s_h = 0x0102;
+static PRUint32 l_h = 0x01020304;
+static PRUint64 ll_h = LL_INIT(0x01020304, 0x05060708);
+
+int main(int argc, char **argv)
+{
+ union {
+ PRUint16 s;
+ PRUint32 l;
+ PRUint64 ll;
+ unsigned char bytes[8];
+ } un;
+
+ un.s = s_h;
+ printf("%u %u\n",
+ un.bytes[0], un.bytes[1]);
+ un.s = PR_htons(un.s);
+ printf("%u %u\n",
+ un.bytes[0], un.bytes[1]);
+ if (memcmp(un.bytes, bytes_n, 2)) {
+ fprintf(stderr, "PR_htons failed\n");
+ exit(1);
+ }
+ un.s = PR_ntohs(un.s);
+ printf("%u %u\n",
+ un.bytes[0], un.bytes[1]);
+ if (un.s != s_h) {
+ fprintf(stderr, "PR_ntohs failed\n");
+ exit(1);
+ }
+
+ un.l = l_h;
+ printf("%u %u %u %u\n",
+ un.bytes[0], un.bytes[1], un.bytes[2], un.bytes[3]);
+ un.l = PR_htonl(un.l);
+ printf("%u %u %u %u\n",
+ un.bytes[0], un.bytes[1], un.bytes[2], un.bytes[3]);
+ if (memcmp(un.bytes, bytes_n, 4)) {
+ fprintf(stderr, "PR_htonl failed\n");
+ exit(1);
+ }
+ un.l = PR_ntohl(un.l);
+ printf("%u %u %u %u\n",
+ un.bytes[0], un.bytes[1], un.bytes[2], un.bytes[3]);
+ if (un.l != l_h) {
+ fprintf(stderr, "PR_ntohl failed\n");
+ exit(1);
+ }
+
+ un.ll = ll_h;
+ printf("%u %u %u %u %u %u %u %u\n",
+ un.bytes[0], un.bytes[1], un.bytes[2], un.bytes[3],
+ un.bytes[4], un.bytes[5], un.bytes[6], un.bytes[7]);
+ un.ll = PR_htonll(un.ll);
+ printf("%u %u %u %u %u %u %u %u\n",
+ un.bytes[0], un.bytes[1], un.bytes[2], un.bytes[3],
+ un.bytes[4], un.bytes[5], un.bytes[6], un.bytes[7]);
+ if (memcmp(un.bytes, bytes_n, 8)) {
+ fprintf(stderr, "PR_htonll failed\n");
+ exit(1);
+ }
+ un.ll = PR_ntohll(un.ll);
+ printf("%u %u %u %u %u %u %u %u\n",
+ un.bytes[0], un.bytes[1], un.bytes[2], un.bytes[3],
+ un.bytes[4], un.bytes[5], un.bytes[6], un.bytes[7]);
+ if (LL_NE(un.ll, ll_h)) {
+ fprintf(stderr, "PR_ntohll failed\n");
+ exit(1);
+ }
+
+ printf("PASS\n");
+ return 0;
+}
diff --git a/nsprpub/pr/tests/obsints.c b/nsprpub/pr/tests/obsints.c
new file mode 100644
index 0000000000..30501ad746
--- /dev/null
+++ b/nsprpub/pr/tests/obsints.c
@@ -0,0 +1,51 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * Test: obsints.c
+ *
+ * Description: make sure that protypes.h defines the obsolete integer
+ * types intn, uintn, uint, int8, uint8, int16, uint16, int32, uint32,
+ * int64, and uint64.
+ */
+
+#include <stdio.h>
+
+#ifdef NO_NSPR_10_SUPPORT
+
+/* nothing to do */
+int main(int argc, char **argv)
+{
+ printf("PASS\n");
+ return 0;
+}
+
+#else /* NO_NSPR_10_SUPPORT */
+
+#include "prtypes.h" /* which includes protypes.h */
+
+int main(int argc, char **argv)
+{
+ /*
+ * Compilation fails if any of these integer types are not
+ * defined by protypes.h.
+ */
+ intn in;
+ uintn uin;
+ uint ui;
+ int8 i8;
+ uint8 ui8;
+ int16 i16;
+ uint16 ui16;
+ int32 i32;
+ uint32 ui32;
+ int64 i64;
+ uint64 ui64;
+
+ printf("PASS\n");
+ return 0;
+}
+
+#endif /* NO_NSPR_10_SUPPORT */
diff --git a/nsprpub/pr/tests/op_2long.c b/nsprpub/pr/tests/op_2long.c
new file mode 100644
index 0000000000..7a6b13122c
--- /dev/null
+++ b/nsprpub/pr/tests/op_2long.c
@@ -0,0 +1,75 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/***********************************************************************
+**
+** Name: op_2long.c
+**
+** Description: Test Program to verify the PR_NAME_TOO_LONG_ERROR
+**
+** Modification History:
+** 03-June-97 AGarcia- Initial version
+***********************************************************************/
+
+/***********************************************************************
+** Includes
+***********************************************************************/
+/* Used to get the command line option */
+#include "prinit.h"
+#include "prmem.h"
+#include "prio.h"
+#include "prerror.h"
+#include <stdio.h>
+#include "plerror.h"
+#include "plgetopt.h"
+
+static PRFileDesc *t1;
+PRIntn error_code;
+
+/*
+ * should exceed any system's maximum file name length
+ * Note: was set at 4096. This is legal on some unix (Linux 2.1+) platforms.
+ *
+ */
+#define TOO_LONG 5000
+
+int main(int argc, char **argv)
+{
+ char nameTooLong[TOO_LONG];
+ int i;
+
+ /* Generate a really long pathname */
+ for (i = 0; i < TOO_LONG - 1; i++) {
+ if (i % 10 == 0) {
+ nameTooLong[i] = '/';
+ } else {
+ nameTooLong[i] = 'a';
+ }
+ }
+ nameTooLong[TOO_LONG - 1] = 0;
+
+ PR_STDIO_INIT();
+ t1 = PR_Open(nameTooLong, PR_RDWR, 0666);
+ if (t1 == NULL) {
+ if (PR_GetError() == PR_NAME_TOO_LONG_ERROR) {
+ PL_PrintError("error code is");
+ printf ("PASS\n");
+ return 0;
+ }
+ else {
+ PL_PrintError("error code is");
+ printf ("FAIL\n");
+ return 1;
+ }
+ }
+
+ else {
+ printf ("Test passed\n");
+ return 0;
+ }
+
+
+
+}
diff --git a/nsprpub/pr/tests/op_excl.c b/nsprpub/pr/tests/op_excl.c
new file mode 100644
index 0000000000..e214af1257
--- /dev/null
+++ b/nsprpub/pr/tests/op_excl.c
@@ -0,0 +1,138 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/***********************************************************************
+**
+** Name: op_excl.c
+**
+** Description: Test Program to verify function of PR_EXCL open flag
+**
+** Modification History:
+** 27-Oct-1999 lth. Initial version
+***********************************************************************/
+
+#include <plgetopt.h>
+#include <nspr.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+/*
+** Test harness infrastructure
+*/
+PRLogModuleInfo *lm;
+PRLogModuleLevel msgLevel = PR_LOG_NONE;
+PRIntn debug = 0;
+PRUint32 failed_already = 0;
+/* end Test harness infrastructure */
+/*
+** Emit help text for this test
+*/
+static void Help( void )
+{
+ printf("op_excl: Help");
+ printf("op_excl [-d]");
+ printf("-d enables debug messages");
+ exit(1);
+} /* end Help() */
+
+
+
+int main(int argc, char **argv)
+{
+ PRFileDesc *fd;
+ PRStatus rv;
+ PRInt32 written;
+ char outBuf[] = "op_excl.c test file";
+#define OUT_SIZE sizeof(outBuf)
+#define NEW_FILENAME "xxxExclNewFile"
+
+ {
+ /*
+ ** Get command line options
+ */
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "hd");
+
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 'd': /* debug */
+ debug = 1;
+ msgLevel = PR_LOG_ERROR;
+ break;
+ case 'h': /* help message */
+ Help();
+ break;
+ default:
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+ }
+
+ lm = PR_NewLogModule("Test"); /* Initialize logging */
+
+ /*
+ ** First, open a file, PR_EXCL, we believe not to exist
+ */
+ fd = PR_Open( NEW_FILENAME, PR_CREATE_FILE | PR_EXCL | PR_WRONLY, 0666 );
+ if ( NULL == fd ) {
+ if (debug) {
+ fprintf( stderr, "Open exclusive. Expected success, got failure\n");
+ }
+ failed_already = 1;
+ goto Finished;
+ }
+
+ written = PR_Write( fd, outBuf, OUT_SIZE );
+ if ( OUT_SIZE != written ) {
+ if (debug) {
+ fprintf( stderr, "Write after open exclusive failed\n");
+ }
+ failed_already = 1;
+ goto Finished;
+ }
+
+ rv = PR_Close(fd);
+ if ( PR_FAILURE == rv ) {
+ if (debug) {
+ fprintf( stderr, "Close after open exclusive failed\n");
+ }
+ failed_already = 1;
+ goto Finished;
+ }
+
+ /*
+ ** Second, open the same file, PR_EXCL, expect it to fail
+ */
+ fd = PR_Open( NEW_FILENAME, PR_CREATE_FILE | PR_EXCL | PR_WRONLY, 0666 );
+ if ( NULL != fd ) {
+ if (debug) {
+ fprintf( stderr, "Open exclusive. Expected failure, got success\n");
+ }
+ failed_already = 1;
+ PR_Close(fd);
+ }
+
+ rv = PR_Delete( NEW_FILENAME );
+ if ( PR_FAILURE == rv ) {
+ if (debug) {
+ fprintf( stderr, "PR_Delete() failed\n");
+ }
+ failed_already = 1;
+ }
+
+Finished:
+ if (debug) {
+ printf("%s\n", (failed_already)? "FAIL" : "PASS");
+ }
+ return( (failed_already == PR_TRUE )? 1 : 0 );
+} /* main() */
+/* end op_excl.c */
+
diff --git a/nsprpub/pr/tests/op_filnf.c b/nsprpub/pr/tests/op_filnf.c
new file mode 100644
index 0000000000..b4ab2fb156
--- /dev/null
+++ b/nsprpub/pr/tests/op_filnf.c
@@ -0,0 +1,51 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/***********************************************************************
+**
+** Name: op_filnf.c
+**
+** Description: Test Program to verify the PR_FILE_NOT_FOUND_ERROR
+** This test program also uses the TRUNCATE option
+**
+** Modification History:
+** 03-June-97 AGarcia- Initial version
+***********************************************************************/
+
+/***********************************************************************
+** Includes
+***********************************************************************/
+/* Used to get the command line option */
+#include "prinit.h"
+#include "prmem.h"
+#include "prio.h"
+#include "prerror.h"
+#include <stdio.h>
+#include "plgetopt.h"
+
+static PRFileDesc *t1;
+PRIntn error_code;
+
+int main(int argc, char **argv)
+{
+ PR_STDIO_INIT();
+ t1 = PR_Open("./tmp-ttools/err03.tmp", PR_TRUNCATE | PR_RDWR, 0666);
+ if (t1 == NULL) {
+ if (PR_GetError() == PR_FILE_NOT_FOUND_ERROR) {
+ printf ("error code is %d \n", PR_GetError());
+ printf ("PASS\n");
+ return 0;
+ }
+ else {
+ printf ("error code is %d \n", PR_GetError());
+ printf ("FAIL\n");
+ return 1;
+ }
+ }
+ PR_Close(t1);
+ printf ("opened a file that should not exist\n");
+ printf ("FAIL\n");
+ return 1;
+}
diff --git a/nsprpub/pr/tests/op_filok.c b/nsprpub/pr/tests/op_filok.c
new file mode 100644
index 0000000000..4f8688b7f1
--- /dev/null
+++ b/nsprpub/pr/tests/op_filok.c
@@ -0,0 +1,48 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/***********************************************************************
+**
+** Name: op_filok.c
+**
+** Description: Test Program to verify the PR_Open finding an existing file.
+**
+** Modification History:
+** 03-June-97 AGarcia- Initial version
+***********************************************************************/
+
+/***********************************************************************
+** Includes
+***********************************************************************/
+/* Used to get the command line option */
+#include "prinit.h"
+#include "prmem.h"
+#include "prio.h"
+#include "prerror.h"
+#include <stdio.h>
+
+static PRFileDesc *t1;
+
+int main(int argc, char **argv)
+{
+ PR_STDIO_INIT();
+
+ t1 = PR_Open(argv[0], PR_RDONLY, 0666);
+
+ if (t1 == NULL) {
+ printf ("error code is %d \n", PR_GetError());
+ printf ("File %s should be found\n", argv[0]);
+ return 1;
+ } else {
+ if (PR_Close(t1) == PR_SUCCESS) {
+ printf ("Test passed \n");
+ return 0;
+ } else {
+ printf ("cannot close file\n");
+ printf ("error code is %d\n", PR_GetError());
+ return 1;
+ }
+ }
+}
diff --git a/nsprpub/pr/tests/op_noacc.c b/nsprpub/pr/tests/op_noacc.c
new file mode 100644
index 0000000000..21ad04be46
--- /dev/null
+++ b/nsprpub/pr/tests/op_noacc.c
@@ -0,0 +1,51 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/***********************************************************************
+**
+** Name: op_noacc.c
+**
+** Description: Test Program to verify the PR_NO_ACCESS_RIGHTS_ERROR in PR_Open
+**
+** Modification History:
+** 03-June-97 AGarcia- Initial version
+***********************************************************************/
+
+/***********************************************************************
+** Includes
+***********************************************************************/
+/* Used to get the command line option */
+#include "prinit.h"
+#include "prmem.h"
+#include "prio.h"
+#include "prerror.h"
+#include <stdio.h>
+#include "plgetopt.h"
+
+static PRFileDesc *err01;
+PRIntn error_code;
+
+int main(int argc, char **argv)
+{
+#ifdef XP_PC
+ printf("op_noacc: Test not valid on MS-Windows.\n\tNo concept of 'mode' on Open() call\n");
+ return(0);
+#endif
+
+
+ PR_STDIO_INIT();
+ err01 = PR_Open("err01.tmp", PR_CREATE_FILE | PR_RDWR, 0);
+ if (err01 == NULL) {
+ int error = PR_GetError();
+ printf ("error code is %d\n", error);
+ if (error == PR_NO_ACCESS_RIGHTS_ERROR) {
+ printf ("PASS\n");
+ return 0;
+ }
+ }
+ printf ("FAIL\n");
+ return 1;
+}
+
diff --git a/nsprpub/pr/tests/op_nofil.c b/nsprpub/pr/tests/op_nofil.c
new file mode 100644
index 0000000000..12d542017c
--- /dev/null
+++ b/nsprpub/pr/tests/op_nofil.c
@@ -0,0 +1,56 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/***********************************************************************
+**
+** Name: op_nofil.c
+**
+** Description: Test Program to verify the PR_FILE_NOT_FOUND_ERROR
+**
+** Modification History:
+** 03-June-97 AGarcia- Initial version
+***********************************************************************/
+
+/***********************************************************************
+** Includes
+***********************************************************************/
+/* Used to get the command line option */
+#include "prinit.h"
+#include "prmem.h"
+#include "prio.h"
+#include "prerror.h"
+#include <stdio.h>
+#include "plgetopt.h"
+
+/*
+ * A file name that cannot exist
+ */
+#define NO_SUCH_FILE "/no/such/file.tmp"
+
+static PRFileDesc *t1;
+
+int main(int argc, char **argv)
+{
+ PR_STDIO_INIT();
+ t1 = PR_Open(NO_SUCH_FILE, PR_RDONLY, 0666);
+ if (t1 == NULL) {
+ if (PR_GetError() == PR_FILE_NOT_FOUND_ERROR) {
+ printf ("error code is PR_FILE_NOT_FOUND_ERROR, as expected\n");
+ printf ("PASS\n");
+ return 0;
+ } else {
+ printf ("error code is %d \n", PR_GetError());
+ printf ("FAIL\n");
+ return 1;
+ }
+ }
+ printf ("File %s exists on this machine!?\n", NO_SUCH_FILE);
+ if (PR_Close(t1) == PR_FAILURE) {
+ printf ("cannot close file\n");
+ printf ("error code is %d \n", PR_GetError());
+ }
+ printf ("FAIL\n");
+ return 1;
+}
diff --git a/nsprpub/pr/tests/openfile.c b/nsprpub/pr/tests/openfile.c
new file mode 100644
index 0000000000..265e041895
--- /dev/null
+++ b/nsprpub/pr/tests/openfile.c
@@ -0,0 +1,113 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * This test calls PR_OpenFile to create a bunch of files
+ * with various file modes.
+ */
+
+#include "prio.h"
+#include "prerror.h"
+#include "prinit.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#define TEMPLATE_FILE_NAME "template.txt"
+
+int main(int argc, char **argv)
+{
+ FILE *template;
+ char buf[32];
+ PRInt32 nbytes;
+ PRFileDesc *fd;
+
+
+ /* Write in text mode. Let stdio deal with line endings. */
+ template = fopen(TEMPLATE_FILE_NAME, "w");
+ fputs("line 1\nline 2\n", template);
+ fclose(template);
+
+ /* Read in binary mode */
+ fd = PR_OpenFile(TEMPLATE_FILE_NAME, PR_RDONLY, 0666);
+ nbytes = PR_Read(fd, buf, sizeof(buf));
+ PR_Close(fd);
+ PR_Delete(TEMPLATE_FILE_NAME);
+
+ fd = PR_OpenFile("tfil0700.txt", PR_RDWR | PR_CREATE_FILE, 0700);
+ if (NULL == fd) {
+ fprintf(stderr, "PR_OpenFile failed (%d, %d)\n",
+ PR_GetError(), PR_GetOSError());
+ exit(1);
+ }
+ PR_Write(fd, buf, nbytes);
+ PR_Close(fd);
+
+ fd = PR_OpenFile("tfil0500.txt", PR_RDWR | PR_CREATE_FILE, 0500);
+ if (NULL == fd) {
+ fprintf(stderr, "PR_OpenFile failed (%d, %d)\n",
+ PR_GetError(), PR_GetOSError());
+ exit(1);
+ }
+ PR_Write(fd, buf, nbytes);
+ PR_Close(fd);
+
+ fd = PR_OpenFile("tfil0400.txt", PR_RDWR | PR_CREATE_FILE, 0400);
+ if (NULL == fd) {
+ fprintf(stderr, "PR_OpenFile failed (%d, %d)\n",
+ PR_GetError(), PR_GetOSError());
+ exit(1);
+ }
+ PR_Write(fd, buf, nbytes);
+ PR_Close(fd);
+
+ fd = PR_OpenFile("tfil0644.txt", PR_RDWR | PR_CREATE_FILE, 0644);
+ if (NULL == fd) {
+ fprintf(stderr, "PR_OpenFile failed (%d, %d)\n",
+ PR_GetError(), PR_GetOSError());
+ exit(1);
+ }
+ PR_Write(fd, buf, nbytes);
+ PR_Close(fd);
+
+ fd = PR_OpenFile("tfil0664.txt", PR_RDWR | PR_CREATE_FILE, 0664);
+ if (NULL == fd) {
+ fprintf(stderr, "PR_OpenFile failed (%d, %d)\n",
+ PR_GetError(), PR_GetOSError());
+ exit(1);
+ }
+ PR_Write(fd, buf, nbytes);
+ PR_Close(fd);
+
+ fd = PR_OpenFile("tfil0660.txt", PR_RDWR | PR_CREATE_FILE, 0660);
+ if (NULL == fd) {
+ fprintf(stderr, "PR_OpenFile failed (%d, %d)\n",
+ PR_GetError(), PR_GetOSError());
+ exit(1);
+ }
+ PR_Write(fd, buf, nbytes);
+ PR_Close(fd);
+
+ fd = PR_OpenFile("tfil0666.txt", PR_RDWR | PR_CREATE_FILE, 0666);
+ if (NULL == fd) {
+ fprintf(stderr, "PR_OpenFile failed (%d, %d)\n",
+ PR_GetError(), PR_GetOSError());
+ exit(1);
+ }
+ PR_Write(fd, buf, nbytes);
+ PR_Close(fd);
+
+ fd = PR_OpenFile("tfil0640.txt", PR_RDWR | PR_CREATE_FILE, 0640);
+ if (NULL == fd) {
+ fprintf(stderr, "PR_OpenFile failed (%d, %d)\n",
+ PR_GetError(), PR_GetOSError());
+ exit(1);
+ }
+ PR_Write(fd, buf, nbytes);
+ PR_Close(fd);
+
+ PR_Cleanup();
+ return 0;
+}
diff --git a/nsprpub/pr/tests/parent.c b/nsprpub/pr/tests/parent.c
new file mode 100644
index 0000000000..f43ce0c3f0
--- /dev/null
+++ b/nsprpub/pr/tests/parent.c
@@ -0,0 +1,131 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+** file: parent.c
+** description: test the process machinery
+*/
+
+#include "prmem.h"
+#include "prprf.h"
+#include "prinit.h"
+#include "prproces.h"
+#include "prinrval.h"
+
+typedef struct Child
+{
+ const char *name;
+ char **argv;
+ PRProcess *process;
+ PRProcessAttr *attr;
+} Child;
+
+/* for the default test 'cvar -c 2000' */
+static char *default_argv[] = {"cvar", "-c", "2000", NULL};
+
+static void PrintUsage(void)
+{
+ PR_fprintf(PR_GetSpecialFD(PR_StandardError),
+ "Usage: parent [-d] child [options]\n");
+}
+
+int main(int argc, char **argv)
+{
+ PRStatus rv;
+ PRInt32 test_status = 1;
+ PRIntervalTime t_start, t_elapsed;
+ PRFileDesc *debug = NULL;
+ Child *child = PR_NEWZAP(Child);
+
+ if (1 == argc)
+ {
+ /* no command-line arguments: run the default test */
+ child->argv = default_argv;
+ }
+ else
+ {
+ argv += 1; /* don't care about our program name */
+ while (*argv != NULL && argv[0][0] == '-')
+ {
+ if (argv[0][1] == 'd') {
+ debug = PR_GetSpecialFD(PR_StandardError);
+ }
+ else
+ {
+ PrintUsage();
+ return 2; /* not sufficient */
+ }
+ argv += 1;
+ }
+ child->argv = argv;
+ }
+
+ if (NULL == *child->argv)
+ {
+ PrintUsage();
+ return 2;
+ }
+
+ child->name = *child->argv;
+ if (NULL != debug) {
+ PR_fprintf(debug, "Forking %s\n", child->name);
+ }
+
+ child->attr = PR_NewProcessAttr();
+ PR_ProcessAttrSetStdioRedirect(
+ child->attr, PR_StandardOutput,
+ PR_GetSpecialFD(PR_StandardOutput));
+ PR_ProcessAttrSetStdioRedirect(
+ child->attr, PR_StandardError,
+ PR_GetSpecialFD(PR_StandardError));
+
+ t_start = PR_IntervalNow();
+ child->process = PR_CreateProcess(
+ 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)
+ {
+ PR_fprintf(
+ debug, "Child was %sforked\n",
+ (0 == test_status) ? "" : "NOT ");
+ if (0 == test_status)
+ PR_fprintf(
+ debug, "PR_CreateProcess took %lu microseconds\n",
+ PR_IntervalToMicroseconds(t_elapsed));
+ }
+
+ if (0 == test_status)
+ {
+ if (NULL != debug) {
+ PR_fprintf(debug, "Waiting for child to exit\n");
+ }
+ rv = PR_WaitProcess(child->process, &test_status);
+ if (PR_SUCCESS == rv)
+ {
+ if (NULL != debug)
+ PR_fprintf(
+ debug, "Child exited %s\n",
+ (0 == test_status) ? "successfully" : "with error");
+ }
+ else
+ {
+ test_status = 1;
+ if (NULL != debug) {
+ PR_fprintf(debug, "PR_WaitProcess failed\n");
+ }
+ }
+ }
+ PR_DELETE(child);
+ PR_Cleanup();
+ return test_status;
+
+} /* main */
+
+/* parent.c */
+
diff --git a/nsprpub/pr/tests/parsetm.c b/nsprpub/pr/tests/parsetm.c
new file mode 100644
index 0000000000..0e25ffe68d
--- /dev/null
+++ b/nsprpub/pr/tests/parsetm.c
@@ -0,0 +1,90 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * This test program should eventually become a full-blown test for
+ * PR_ParseTimeString. Right now it just verifies that PR_ParseTimeString
+ * doesn't crash on an out-of-range time string (bug 480740).
+ */
+
+#include "prtime.h"
+
+#include <time.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+PRBool debug_mode = PR_TRUE;
+
+static char *dayOfWeek[] =
+{ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "???" };
+static char *month[] =
+{ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "???"
+};
+
+static void PrintExplodedTime(const PRExplodedTime *et) {
+ PRInt32 totalOffset;
+ PRInt32 hourOffset, minOffset;
+ const char *sign;
+
+ /* Print day of the week, month, day, hour, minute, and second */
+ if (debug_mode) printf("%s %s %ld %02ld:%02ld:%02ld ",
+ dayOfWeek[et->tm_wday], month[et->tm_month], et->tm_mday,
+ et->tm_hour, et->tm_min, et->tm_sec);
+
+ /* Print time zone */
+ totalOffset = et->tm_params.tp_gmt_offset + et->tm_params.tp_dst_offset;
+ if (totalOffset == 0) {
+ if (debug_mode) {
+ printf("UTC ");
+ }
+ } else {
+ sign = "+";
+ if (totalOffset < 0) {
+ totalOffset = -totalOffset;
+ sign = "-";
+ }
+ hourOffset = totalOffset / 3600;
+ minOffset = (totalOffset % 3600) / 60;
+ if (debug_mode) {
+ printf("%s%02ld%02ld ", sign, hourOffset, minOffset);
+ }
+ }
+
+ /* Print year */
+ if (debug_mode) {
+ printf("%hd", et->tm_year);
+ }
+}
+
+int main(int argc, char **argv)
+{
+ PRTime ct;
+ PRExplodedTime et;
+ PRStatus rv;
+ char *sp1 = "Sat, 1 Jan 3001 00:00:00"; /* no time zone */
+ char *sp2 = "Fri, 31 Dec 3000 23:59:60"; /* no time zone, not normalized */
+
+#if _MSC_VER >= 1400 && !defined(WINCE)
+ /* Run this test in the US Pacific Time timezone. */
+ _putenv_s("TZ", "PST8PDT");
+ _tzset();
+#endif
+
+ rv = PR_ParseTimeString(sp1, PR_FALSE, &ct);
+ printf("rv = %d\n", rv);
+ PR_ExplodeTime(ct, PR_GMTParameters, &et);
+ PrintExplodedTime(&et);
+ printf("\n");
+
+ rv = PR_ParseTimeString(sp2, PR_FALSE, &ct);
+ printf("rv = %d\n", rv);
+ PR_ExplodeTime(ct, PR_GMTParameters, &et);
+ PrintExplodedTime(&et);
+ printf("\n");
+
+ return 0;
+}
diff --git a/nsprpub/pr/tests/peek.c b/nsprpub/pr/tests/peek.c
new file mode 100644
index 0000000000..4dce8299dd
--- /dev/null
+++ b/nsprpub/pr/tests/peek.c
@@ -0,0 +1,362 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * A test case for the PR_MSG_PEEK flag of PR_Recv().
+ *
+ * Test both blocking and non-blocking sockets.
+ */
+
+#include "nspr.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define BUFFER_SIZE 1024
+
+static int iterations = 10;
+
+/*
+ * In iteration i, recv_amount[i] is the number of bytes we
+ * wish to receive, and send_amount[i] is the number of bytes
+ * we actually send. Therefore, the number of elements in the
+ * recv_amount or send_amount array should equal to 'iterations'.
+ * For this test to pass we need to ensure that
+ * recv_amount[i] <= BUFFER_SIZE,
+ * send_amount[i] <= BUFFER_SIZE,
+ * send_amount[i] <= recv_amount[i].
+ */
+static PRInt32 recv_amount[10] = {
+ 16, 128, 256, 1024, 512, 512, 128, 256, 32, 32
+};
+static PRInt32 send_amount[10] = {
+ 16, 64, 128, 1024, 512, 256, 128, 64, 16, 32
+};
+
+/* Blocking I/O */
+static void ServerB(void *arg)
+{
+ PRFileDesc *listenSock = (PRFileDesc *) arg;
+ PRFileDesc *sock;
+ char buf[BUFFER_SIZE];
+ PRInt32 nbytes;
+ int i;
+ int j;
+
+ sock = PR_Accept(listenSock, NULL, PR_INTERVAL_NO_TIMEOUT);
+ if (NULL == sock) {
+ fprintf(stderr, "PR_Accept failed\n");
+ exit(1);
+ }
+
+ for (i = 0; i < iterations; i++) {
+ memset(buf, 0, sizeof(buf));
+ nbytes = PR_Recv(sock, buf, recv_amount[i],
+ PR_MSG_PEEK, PR_INTERVAL_NO_TIMEOUT);
+ if (-1 == nbytes) {
+ fprintf(stderr, "PR_Recv failed\n");
+ exit(1);
+ }
+ if (send_amount[i] != nbytes) {
+ fprintf(stderr, "PR_Recv returned %d, absurd!\n", nbytes);
+ exit(1);
+ }
+ for (j = 0; j < nbytes; j++) {
+ if (buf[j] != 2*i) {
+ fprintf(stderr, "byte %d should be %d but is %d\n",
+ j, 2*i, buf[j]);
+ exit(1);
+ }
+ }
+ fprintf(stderr, "server: peeked expected data\n");
+
+ memset(buf, 0, sizeof(buf));
+ nbytes = PR_Recv(sock, buf, recv_amount[i],
+ PR_MSG_PEEK, PR_INTERVAL_NO_TIMEOUT);
+ if (-1 == nbytes) {
+ fprintf(stderr, "PR_Recv failed\n");
+ exit(1);
+ }
+ if (send_amount[i] != nbytes) {
+ fprintf(stderr, "PR_Recv returned %d, absurd!\n", nbytes);
+ exit(1);
+ }
+ for (j = 0; j < nbytes; j++) {
+ if (buf[j] != 2*i) {
+ fprintf(stderr, "byte %d should be %d but is %d\n",
+ j, 2*i, buf[j]);
+ exit(1);
+ }
+ }
+ fprintf(stderr, "server: peeked expected data\n");
+
+ memset(buf, 0, sizeof(buf));
+ nbytes = PR_Recv(sock, buf, recv_amount[i],
+ 0, PR_INTERVAL_NO_TIMEOUT);
+ if (-1 == nbytes) {
+ fprintf(stderr, "PR_Recv failed\n");
+ exit(1);
+ }
+ if (send_amount[i] != nbytes) {
+ fprintf(stderr, "PR_Recv returned %d, absurd!\n", nbytes);
+ exit(1);
+ }
+ for (j = 0; j < nbytes; j++) {
+ if (buf[j] != 2*i) {
+ fprintf(stderr, "byte %d should be %d but is %d\n",
+ j, 2*i, buf[j]);
+ exit(1);
+ }
+ }
+ fprintf(stderr, "server: received expected data\n");
+
+ PR_Sleep(PR_SecondsToInterval(1));
+ memset(buf, 2*i+1, send_amount[i]);
+ nbytes = PR_Send(sock, buf, send_amount[i],
+ 0, PR_INTERVAL_NO_TIMEOUT);
+ if (-1 == nbytes) {
+ fprintf(stderr, "PR_Send failed\n");
+ exit(1);
+ }
+ if (send_amount[i] != nbytes) {
+ fprintf(stderr, "PR_Send returned %d, absurd!\n", nbytes);
+ exit(1);
+ }
+ }
+ if (PR_Close(sock) == PR_FAILURE) {
+ fprintf(stderr, "PR_Close failed\n");
+ exit(1);
+ }
+}
+
+/* Non-blocking I/O */
+static void ClientNB(void *arg)
+{
+ PRFileDesc *sock;
+ PRSocketOptionData opt;
+ PRUint16 port = (PRUint16) arg;
+ PRNetAddr addr;
+ char buf[BUFFER_SIZE];
+ PRPollDesc pd;
+ PRInt32 npds;
+ PRInt32 nbytes;
+ int i;
+ int j;
+
+ sock = PR_OpenTCPSocket(PR_AF_INET6);
+ if (NULL == sock) {
+ fprintf(stderr, "PR_OpenTCPSocket failed\n");
+ exit(1);
+ }
+ opt.option = PR_SockOpt_Nonblocking;
+ opt.value.non_blocking = PR_TRUE;
+ if (PR_SetSocketOption(sock, &opt) == PR_FAILURE) {
+ fprintf(stderr, "PR_SetSocketOption failed\n");
+ exit(1);
+ }
+ memset(&addr, 0, sizeof(addr));
+ if (PR_SetNetAddr(PR_IpAddrLoopback, PR_AF_INET6, port, &addr)
+ == PR_FAILURE) {
+ fprintf(stderr, "PR_SetNetAddr failed\n");
+ exit(1);
+ }
+ if (PR_Connect(sock, &addr, PR_INTERVAL_NO_TIMEOUT) == PR_FAILURE) {
+ if (PR_GetError() != PR_IN_PROGRESS_ERROR) {
+ fprintf(stderr, "PR_Connect failed\n");
+ exit(1);
+ }
+ pd.fd = sock;
+ pd.in_flags = PR_POLL_WRITE | PR_POLL_EXCEPT;
+ npds = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT);
+ if (-1 == npds) {
+ fprintf(stderr, "PR_Poll failed\n");
+ exit(1);
+ }
+ if (1 != npds) {
+ fprintf(stderr, "PR_Poll returned %d, absurd!\n", npds);
+ exit(1);
+ }
+ if (PR_GetConnectStatus(&pd) == PR_FAILURE) {
+ fprintf(stderr, "PR_GetConnectStatus failed\n");
+ exit(1);
+ }
+ }
+
+ for (i = 0; i < iterations; i++) {
+ PR_Sleep(PR_SecondsToInterval(1));
+ memset(buf, 2*i, send_amount[i]);
+ while ((nbytes = PR_Send(sock, buf, send_amount[i],
+ 0, PR_INTERVAL_NO_TIMEOUT)) == -1) {
+ if (PR_GetError() != PR_WOULD_BLOCK_ERROR) {
+ fprintf(stderr, "PR_Send failed\n");
+ exit(1);
+ }
+ pd.fd = sock;
+ pd.in_flags = PR_POLL_WRITE;
+ npds = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT);
+ if (-1 == npds) {
+ fprintf(stderr, "PR_Poll failed\n");
+ exit(1);
+ }
+ if (1 != npds) {
+ fprintf(stderr, "PR_Poll returned %d, absurd!\n", npds);
+ exit(1);
+ }
+ }
+ if (send_amount[i] != nbytes) {
+ fprintf(stderr, "PR_Send returned %d, absurd!\n", nbytes);
+ exit(1);
+ }
+
+ memset(buf, 0, sizeof(buf));
+ while ((nbytes = PR_Recv(sock, buf, recv_amount[i],
+ PR_MSG_PEEK, PR_INTERVAL_NO_TIMEOUT)) == -1) {
+ if (PR_GetError() != PR_WOULD_BLOCK_ERROR) {
+ fprintf(stderr, "PR_Recv failed\n");
+ exit(1);
+ }
+ pd.fd = sock;
+ pd.in_flags = PR_POLL_READ;
+ npds = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT);
+ if (-1 == npds) {
+ fprintf(stderr, "PR_Poll failed\n");
+ exit(1);
+ }
+ if (1 != npds) {
+ fprintf(stderr, "PR_Poll returned %d, absurd!\n", npds);
+ exit(1);
+ }
+ }
+ if (send_amount[i] != nbytes) {
+ fprintf(stderr, "PR_Recv returned %d, absurd!\n", nbytes);
+ exit(1);
+ }
+ for (j = 0; j < nbytes; j++) {
+ if (buf[j] != 2*i+1) {
+ fprintf(stderr, "byte %d should be %d but is %d\n",
+ j, 2*i+1, buf[j]);
+ exit(1);
+ }
+ }
+ fprintf(stderr, "client: peeked expected data\n");
+
+ memset(buf, 0, sizeof(buf));
+ nbytes = PR_Recv(sock, buf, recv_amount[i],
+ PR_MSG_PEEK, PR_INTERVAL_NO_TIMEOUT);
+ if (-1 == nbytes) {
+ fprintf(stderr, "PR_Recv failed\n");
+ exit(1);
+ }
+ if (send_amount[i] != nbytes) {
+ fprintf(stderr, "PR_Recv returned %d, absurd!\n", nbytes);
+ exit(1);
+ }
+ for (j = 0; j < nbytes; j++) {
+ if (buf[j] != 2*i+1) {
+ fprintf(stderr, "byte %d should be %d but is %d\n",
+ j, 2*i+1, buf[j]);
+ exit(1);
+ }
+ }
+ fprintf(stderr, "client: peeked expected data\n");
+
+ memset(buf, 0, sizeof(buf));
+ nbytes = PR_Recv(sock, buf, recv_amount[i],
+ 0, PR_INTERVAL_NO_TIMEOUT);
+ if (-1 == nbytes) {
+ fprintf(stderr, "PR_Recv failed\n");
+ exit(1);
+ }
+ if (send_amount[i] != nbytes) {
+ fprintf(stderr, "PR_Recv returned %d, absurd!\n", nbytes);
+ exit(1);
+ }
+ for (j = 0; j < nbytes; j++) {
+ if (buf[j] != 2*i+1) {
+ fprintf(stderr, "byte %d should be %d but is %d\n",
+ j, 2*i+1, buf[j]);
+ exit(1);
+ }
+ }
+ fprintf(stderr, "client: received expected data\n");
+ }
+ if (PR_Close(sock) == PR_FAILURE) {
+ fprintf(stderr, "PR_Close failed\n");
+ exit(1);
+ }
+}
+
+static void
+RunTest(PRThreadScope scope, PRFileDesc *listenSock, PRUint16 port)
+{
+ PRThread *server, *client;
+
+ server = PR_CreateThread(PR_USER_THREAD, ServerB, listenSock,
+ PR_PRIORITY_NORMAL, scope, PR_JOINABLE_THREAD, 0);
+ if (NULL == server) {
+ fprintf(stderr, "PR_CreateThread failed\n");
+ exit(1);
+ }
+ client = PR_CreateThread(
+ PR_USER_THREAD, ClientNB, (void *) port,
+ PR_PRIORITY_NORMAL, scope, PR_JOINABLE_THREAD, 0);
+ if (NULL == client) {
+ fprintf(stderr, "PR_CreateThread failed\n");
+ exit(1);
+ }
+
+ if (PR_JoinThread(server) == PR_FAILURE) {
+ fprintf(stderr, "PR_JoinThread failed\n");
+ exit(1);
+ }
+ if (PR_JoinThread(client) == PR_FAILURE) {
+ fprintf(stderr, "PR_JoinThread failed\n");
+ exit(1);
+ }
+}
+
+int main(int argc, char **argv)
+{
+ PRFileDesc *listenSock;
+ PRNetAddr addr;
+ PRUint16 port;
+
+ listenSock = PR_OpenTCPSocket(PR_AF_INET6);
+ if (NULL == listenSock) {
+ fprintf(stderr, "PR_OpenTCPSocket failed\n");
+ exit(1);
+ }
+ memset(&addr, 0, sizeof(addr));
+ if (PR_SetNetAddr(PR_IpAddrAny, PR_AF_INET6, 0, &addr) == PR_FAILURE) {
+ fprintf(stderr, "PR_SetNetAddr failed\n");
+ exit(1);
+ }
+ if (PR_Bind(listenSock, &addr) == PR_FAILURE) {
+ fprintf(stderr, "PR_Bind failed\n");
+ exit(1);
+ }
+ if (PR_GetSockName(listenSock, &addr) == PR_FAILURE) {
+ fprintf(stderr, "PR_GetSockName failed\n");
+ exit(1);
+ }
+ port = PR_ntohs(addr.ipv6.port);
+ if (PR_Listen(listenSock, 5) == PR_FAILURE) {
+ fprintf(stderr, "PR_Listen failed\n");
+ exit(1);
+ }
+
+ fprintf(stderr, "Running the test with local threads\n");
+ RunTest(PR_LOCAL_THREAD, listenSock, port);
+ fprintf(stderr, "Running the test with global threads\n");
+ RunTest(PR_GLOBAL_THREAD, listenSock, port);
+
+ if (PR_Close(listenSock) == PR_FAILURE) {
+ fprintf(stderr, "PR_Close failed\n");
+ exit(1);
+ }
+ printf("PASS\n");
+ return 0;
+}
diff --git a/nsprpub/pr/tests/perf.c b/nsprpub/pr/tests/perf.c
new file mode 100644
index 0000000000..cd8ac1439b
--- /dev/null
+++ b/nsprpub/pr/tests/perf.c
@@ -0,0 +1,447 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nspr.h"
+#include "plgetopt.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int _debug_on = 0;
+#define DPRINTF(arg) if (_debug_on) printf arg
+
+#include "obsolete/prsem.h"
+
+PRLock *lock;
+PRMonitor *mon;
+PRMonitor *mon2;
+
+#define DEFAULT_COUNT 1000
+
+PRInt32 count;
+
+static void nop(int a, int b, int c)
+{
+}
+
+static void LocalProcedureCall(void)
+{
+ PRInt32 i;
+
+ for (i = 0; i < count; i++) {
+ nop(i, i, 5);
+ }
+}
+
+static void DLLProcedureCall(void)
+{
+ PRInt32 i;
+ PRThreadState state;
+ PRThread *self = PR_GetCurrentThread();
+
+ for (i = 0; i < count; i++) {
+ state = PR_GetThreadState(self);
+ }
+}
+
+static void Now(void)
+{
+ PRInt32 i;
+ PRTime time;
+
+ for (i = 0; i < count; i++) {
+ time = PR_Now();
+ }
+}
+
+static void Interval(void)
+{
+ PRInt32 i;
+ PRIntervalTime time;
+
+ for (i = 0; i < count; i++) {
+ time = PR_IntervalNow();
+ }
+}
+
+static void IdleLock(void)
+{
+ PRInt32 i;
+
+ for (i = 0; i < count; i++) {
+ PR_Lock(lock);
+ PR_Unlock(lock);
+ }
+}
+
+static void IdleMonitor(void)
+{
+ PRInt32 i;
+
+ for (i = 0; i < count; i++) {
+ PR_EnterMonitor(mon);
+ PR_ExitMonitor(mon);
+ }
+}
+
+static void IdleCMonitor(void)
+{
+ PRInt32 i;
+
+ for (i = 0; i < count; i++) {
+ PR_CEnterMonitor((void*)7);
+ PR_CExitMonitor((void*)7);
+ }
+}
+
+/************************************************************************/
+
+static void PR_CALLBACK dull(void *arg)
+{
+}
+
+static void CDThread(void)
+{
+ PRInt32 i;
+ int num_threads = count;
+
+ /*
+ * Cannot create too many threads
+ */
+ if (num_threads > 1000) {
+ num_threads = 1000;
+ }
+
+ for (i = 0; i < num_threads; i++) {
+ PRThread *t = PR_CreateThread(PR_USER_THREAD,
+ dull, 0,
+ PR_PRIORITY_NORMAL,
+ PR_LOCAL_THREAD,
+ PR_UNJOINABLE_THREAD,
+ 0);
+ if (NULL == t) {
+ fprintf(stderr, "CDThread: cannot create thread %3d\n", i);
+ } else {
+ DPRINTF(("CDThread: created thread %3d \n",i));
+ }
+ PR_Sleep(0);
+ }
+}
+
+static int alive;
+static int cxq;
+
+static void PR_CALLBACK CXReader(void *arg)
+{
+ PRInt32 i, n;
+
+ PR_EnterMonitor(mon);
+ n = count / 2;
+ for (i = 0; i < n; i++) {
+ while (cxq == 0) {
+ DPRINTF(("CXReader: thread = 0x%lx waiting\n",
+ PR_GetCurrentThread()));
+ PR_Wait(mon, PR_INTERVAL_NO_TIMEOUT);
+ }
+ --cxq;
+ PR_Notify(mon);
+ }
+ PR_ExitMonitor(mon);
+
+ PR_EnterMonitor(mon2);
+ --alive;
+ PR_Notify(mon2);
+ PR_ExitMonitor(mon2);
+ DPRINTF(("CXReader: thread = 0x%lx exiting\n", PR_GetCurrentThread()));
+}
+
+static void PR_CALLBACK CXWriter(void *arg)
+{
+ PRInt32 i, n;
+
+ PR_EnterMonitor(mon);
+ n = count / 2;
+ for (i = 0; i < n; i++) {
+ while (cxq == 1) {
+ DPRINTF(("CXWriter: thread = 0x%lx waiting\n",
+ PR_GetCurrentThread()));
+ PR_Wait(mon, PR_INTERVAL_NO_TIMEOUT);
+ }
+ ++cxq;
+ PR_Notify(mon);
+ }
+ PR_ExitMonitor(mon);
+
+ PR_EnterMonitor(mon2);
+ --alive;
+ PR_Notify(mon2);
+ PR_ExitMonitor(mon2);
+ DPRINTF(("CXWriter: thread = 0x%lx exiting\n", PR_GetCurrentThread()));
+}
+
+static void ContextSwitch(PRThreadScope scope1, PRThreadScope scope2)
+{
+ PRThread *t1, *t2;
+
+ PR_EnterMonitor(mon2);
+ alive = 2;
+ cxq = 0;
+
+ t1 = PR_CreateThread(PR_USER_THREAD,
+ CXReader, 0,
+ PR_PRIORITY_NORMAL,
+ scope1,
+ PR_UNJOINABLE_THREAD,
+ 0);
+ if (NULL == t1) {
+ fprintf(stderr, "ContextSwitch: cannot create thread\n");
+ } else {
+ DPRINTF(("ContextSwitch: created %s thread = 0x%lx\n",
+ (scope1 == PR_GLOBAL_THREAD ?
+ "PR_GLOBAL_THREAD" : "PR_LOCAL_THREAD"),
+ t1));
+ }
+ t2 = PR_CreateThread(PR_USER_THREAD,
+ CXWriter, 0,
+ PR_PRIORITY_NORMAL,
+ scope2,
+ PR_UNJOINABLE_THREAD,
+ 0);
+ if (NULL == t2) {
+ fprintf(stderr, "ContextSwitch: cannot create thread\n");
+ } else {
+ DPRINTF(("ContextSwitch: created %s thread = 0x%lx\n",
+ (scope2 == PR_GLOBAL_THREAD ?
+ "PR_GLOBAL_THREAD" : "PR_LOCAL_THREAD"),
+ t2));
+ }
+
+ /* Wait for both of the threads to exit */
+ while (alive) {
+ PR_Wait(mon2, PR_INTERVAL_NO_TIMEOUT);
+ }
+ PR_ExitMonitor(mon2);
+}
+
+static void ContextSwitchUU(void)
+{
+ ContextSwitch(PR_LOCAL_THREAD, PR_LOCAL_THREAD);
+}
+
+static void ContextSwitchUK(void)
+{
+ ContextSwitch(PR_LOCAL_THREAD, PR_GLOBAL_THREAD);
+}
+
+static void ContextSwitchKU(void)
+{
+ ContextSwitch(PR_GLOBAL_THREAD, PR_LOCAL_THREAD);
+}
+
+static void ContextSwitchKK(void)
+{
+ ContextSwitch(PR_GLOBAL_THREAD, PR_GLOBAL_THREAD);
+}
+
+/************************************************************************/
+
+static void PR_CALLBACK SemaThread(void *argSema)
+{
+ PRSemaphore **sem = (PRSemaphore **)argSema;
+ PRInt32 i, n;
+
+ n = count / 2;
+ for (i = 0; i < n; i++) {
+ DPRINTF(("SemaThread: thread = 0x%lx waiting on sem = 0x%lx\n",
+ PR_GetCurrentThread(), sem[0]));
+ PR_WaitSem(sem[0]);
+ DPRINTF(("SemaThread: thread = 0x%lx posting on sem = 0x%lx\n",
+ PR_GetCurrentThread(), sem[1]));
+ PR_PostSem(sem[1]);
+ }
+
+ PR_EnterMonitor(mon2);
+ --alive;
+ PR_Notify(mon2);
+ PR_ExitMonitor(mon2);
+ DPRINTF(("SemaThread: thread = 0x%lx exiting\n", PR_GetCurrentThread()));
+}
+
+static PRSemaphore *sem_set1[2];
+static PRSemaphore *sem_set2[2];
+
+static void SemaContextSwitch(PRThreadScope scope1, PRThreadScope scope2)
+{
+ PRThread *t1, *t2;
+ sem_set1[0] = PR_NewSem(1);
+ sem_set1[1] = PR_NewSem(0);
+ sem_set2[0] = sem_set1[1];
+ sem_set2[1] = sem_set1[0];
+
+ PR_EnterMonitor(mon2);
+ alive = 2;
+ cxq = 0;
+
+ t1 = PR_CreateThread(PR_USER_THREAD,
+ SemaThread,
+ sem_set1,
+ PR_PRIORITY_NORMAL,
+ scope1,
+ PR_UNJOINABLE_THREAD,
+ 0);
+ if (NULL == t1) {
+ fprintf(stderr, "SemaContextSwitch: cannot create thread\n");
+ } else {
+ DPRINTF(("SemaContextSwitch: created %s thread = 0x%lx\n",
+ (scope1 == PR_GLOBAL_THREAD ?
+ "PR_GLOBAL_THREAD" : "PR_LOCAL_THREAD"),
+ t1));
+ }
+ t2 = PR_CreateThread(PR_USER_THREAD,
+ SemaThread,
+ sem_set2,
+ PR_PRIORITY_NORMAL,
+ scope2,
+ PR_UNJOINABLE_THREAD,
+ 0);
+ if (NULL == t2) {
+ fprintf(stderr, "SemaContextSwitch: cannot create thread\n");
+ } else {
+ DPRINTF(("SemaContextSwitch: created %s thread = 0x%lx\n",
+ (scope2 == PR_GLOBAL_THREAD ?
+ "PR_GLOBAL_THREAD" : "PR_LOCAL_THREAD"),
+ t2));
+ }
+
+ /* Wait for both of the threads to exit */
+ while (alive) {
+ PR_Wait(mon2, PR_INTERVAL_NO_TIMEOUT);
+ }
+ PR_ExitMonitor(mon2);
+
+ PR_DestroySem(sem_set1[0]);
+ PR_DestroySem(sem_set1[1]);
+}
+
+static void SemaContextSwitchUU(void)
+{
+ SemaContextSwitch(PR_LOCAL_THREAD, PR_LOCAL_THREAD);
+}
+
+static void SemaContextSwitchUK(void)
+{
+ SemaContextSwitch(PR_LOCAL_THREAD, PR_GLOBAL_THREAD);
+}
+
+static void SemaContextSwitchKU(void)
+{
+ SemaContextSwitch(PR_GLOBAL_THREAD, PR_LOCAL_THREAD);
+}
+
+static void SemaContextSwitchKK(void)
+{
+ SemaContextSwitch(PR_GLOBAL_THREAD, PR_GLOBAL_THREAD);
+}
+
+
+/************************************************************************/
+
+static void Measure(void (*func)(void), const char *msg)
+{
+ PRIntervalTime start, stop;
+ double d;
+
+ start = PR_IntervalNow();
+ (*func)();
+ stop = PR_IntervalNow() - start;
+ d = (double)PR_IntervalToMicroseconds(stop);
+
+ printf("%40s: %6.2f usec\n", msg, d / count);
+}
+
+int main(int argc, char **argv)
+{
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "dc:");
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 'd': /* debug mode */
+ _debug_on = 1;
+ break;
+ case 'c': /* loop count */
+ count = atoi(opt->value);
+ break;
+ default:
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ if (0 == count) {
+ count = DEFAULT_COUNT;
+ }
+
+ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
+ PR_BlockClockInterrupts();
+ PR_UnblockClockInterrupts();
+ PR_STDIO_INIT();
+
+ lock = PR_NewLock();
+ mon = PR_NewMonitor();
+ mon2 = PR_NewMonitor();
+
+ Measure(LocalProcedureCall, "local procedure call overhead");
+ Measure(DLLProcedureCall, "DLL procedure call overhead");
+ Measure(Now, "current calendar time");
+ Measure(Interval, "interval time");
+ Measure(IdleLock, "idle lock lock/unlock pair");
+ Measure(IdleMonitor, "idle monitor entry/exit pair");
+ Measure(IdleCMonitor, "idle cache monitor entry/exit pair");
+ Measure(CDThread, "create/destroy thread pair");
+ Measure(ContextSwitchUU, "context switch - user/user");
+ Measure(ContextSwitchUK, "context switch - user/kernel");
+ Measure(ContextSwitchKU, "context switch - kernel/user");
+ Measure(ContextSwitchKK, "context switch - kernel/kernel");
+ Measure(SemaContextSwitchUU, "sema context switch - user/user");
+ Measure(SemaContextSwitchUK, "sema context switch - user/kernel");
+ Measure(SemaContextSwitchKU, "sema context switch - kernel/user");
+ Measure(SemaContextSwitchKK, "sema context switch - kernel/kernel");
+
+ printf("--------------\n");
+ printf("Adding 7 additional CPUs\n");
+
+ PR_SetConcurrency(8);
+ printf("--------------\n");
+
+ Measure(LocalProcedureCall, "local procedure call overhead");
+ Measure(DLLProcedureCall, "DLL procedure call overhead");
+ Measure(Now, "current calendar time");
+ Measure(Interval, "interval time");
+ Measure(IdleLock, "idle lock lock/unlock pair");
+ Measure(IdleMonitor, "idle monitor entry/exit pair");
+ Measure(IdleCMonitor, "idle cache monitor entry/exit pair");
+ Measure(CDThread, "create/destroy thread pair");
+ Measure(ContextSwitchUU, "context switch - user/user");
+ Measure(ContextSwitchUK, "context switch - user/kernel");
+ Measure(ContextSwitchKU, "context switch - kernel/user");
+ Measure(ContextSwitchKK, "context switch - kernel/kernel");
+ Measure(SemaContextSwitchUU, "sema context switch - user/user");
+ Measure(SemaContextSwitchUK, "sema context switch - user/kernel");
+ Measure(SemaContextSwitchKU, "sema context switch - kernel/user");
+ Measure(SemaContextSwitchKK, "sema context switch - kernel/kernel");
+
+ PR_DestroyLock(lock);
+ PR_DestroyMonitor(mon);
+ PR_DestroyMonitor(mon2);
+
+ PR_Cleanup();
+ return 0;
+}
diff --git a/nsprpub/pr/tests/pipeping.c b/nsprpub/pr/tests/pipeping.c
new file mode 100644
index 0000000000..26b63c659d
--- /dev/null
+++ b/nsprpub/pr/tests/pipeping.c
@@ -0,0 +1,158 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * File: pipeping.c
+ *
+ * Description:
+ * This test runs in conjunction with the pipepong test.
+ * This test creates two pipes and redirects the stdin and
+ * stdout of the pipepong test to the pipes. Then this
+ * test writes "ping" to the pipepong test and the pipepong
+ * test writes "pong" back. To run this pair of tests,
+ * just invoke pipeping.
+ *
+ * Tested areas: process creation, pipes, file descriptor
+ * inheritance, standard I/O redirection.
+ */
+
+#include "prerror.h"
+#include "prio.h"
+#include "prproces.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef XP_OS2
+static char *child_argv[] = { "pipepong.exe", NULL };
+#else
+static char *child_argv[] = { "pipepong", NULL };
+#endif
+
+#define NUM_ITERATIONS 10
+
+int main(int argc, char **argv)
+{
+ PRFileDesc *in_pipe[2];
+ PRFileDesc *out_pipe[2];
+ PRStatus status;
+ PRProcess *process;
+ PRProcessAttr *attr;
+ char buf[1024];
+ PRInt32 nBytes;
+ PRInt32 exitCode;
+ int idx;
+
+ status = PR_CreatePipe(&in_pipe[0], &in_pipe[1]);
+ if (status == PR_FAILURE) {
+ fprintf(stderr, "PR_CreatePipe failed\n");
+ exit(1);
+ }
+ status = PR_CreatePipe(&out_pipe[0], &out_pipe[1]);
+ if (status == PR_FAILURE) {
+ fprintf(stderr, "PR_CreatePipe failed\n");
+ exit(1);
+ }
+
+ status = PR_SetFDInheritable(in_pipe[0], PR_FALSE);
+ if (status == PR_FAILURE) {
+ fprintf(stderr, "PR_SetFDInheritable failed\n");
+ exit(1);
+ }
+ status = PR_SetFDInheritable(in_pipe[1], PR_TRUE);
+ if (status == PR_FAILURE) {
+ fprintf(stderr, "PR_SetFDInheritable failed\n");
+ exit(1);
+ }
+ status = PR_SetFDInheritable(out_pipe[0], PR_TRUE);
+ if (status == PR_FAILURE) {
+ fprintf(stderr, "PR_SetFDInheritable failed\n");
+ exit(1);
+ }
+ status = PR_SetFDInheritable(out_pipe[1], PR_FALSE);
+ if (status == PR_FAILURE) {
+ fprintf(stderr, "PR_SetFDInheritable failed\n");
+ exit(1);
+ }
+
+ attr = PR_NewProcessAttr();
+ if (attr == NULL) {
+ fprintf(stderr, "PR_NewProcessAttr failed\n");
+ exit(1);
+ }
+
+ PR_ProcessAttrSetStdioRedirect(attr, PR_StandardInput, out_pipe[0]);
+ PR_ProcessAttrSetStdioRedirect(attr, PR_StandardOutput, in_pipe[1]);
+
+ process = PR_CreateProcess(child_argv[0], child_argv, NULL, attr);
+ if (process == NULL) {
+ fprintf(stderr, "PR_CreateProcess failed\n");
+ exit(1);
+ }
+ PR_DestroyProcessAttr(attr);
+ status = PR_Close(out_pipe[0]);
+ if (status == PR_FAILURE) {
+ fprintf(stderr, "PR_Close failed\n");
+ exit(1);
+ }
+ status = PR_Close(in_pipe[1]);
+ if (status == PR_FAILURE) {
+ fprintf(stderr, "PR_Close failed\n");
+ exit(1);
+ }
+
+ for (idx = 0; idx < NUM_ITERATIONS; idx++) {
+ strcpy(buf, "ping");
+ printf("ping process: sending \"%s\"\n", buf);
+ nBytes = PR_Write(out_pipe[1], buf, 5);
+ if (nBytes == -1) {
+ fprintf(stderr, "PR_Write failed: (%d, %d)\n", PR_GetError(),
+ PR_GetOSError());
+ exit(1);
+ }
+ memset(buf, 0, sizeof(buf));
+ nBytes = PR_Read(in_pipe[0], buf, sizeof(buf));
+ if (nBytes == -1) {
+ fprintf(stderr, "PR_Read failed: (%d, %d)\n",
+ PR_GetError(), PR_GetOSError());
+ exit(1);
+ }
+ printf("ping process: received \"%s\"\n", buf);
+ if (nBytes != 5) {
+ fprintf(stderr, "ping process: expected 5 bytes but got %d bytes\n",
+ nBytes);
+ exit(1);
+ }
+ if (strcmp(buf, "pong") != 0) {
+ fprintf(stderr, "ping process: expected \"pong\" but got \"%s\"\n",
+ buf);
+ exit(1);
+ }
+ }
+
+ status = PR_Close(in_pipe[0]);
+ if (status == PR_FAILURE) {
+ fprintf(stderr, "PR_Close failed\n");
+ exit(1);
+ }
+ status = PR_Close(out_pipe[1]);
+ if (status == PR_FAILURE) {
+ fprintf(stderr, "PR_Close failed\n");
+ exit(1);
+ }
+ status = PR_WaitProcess(process, &exitCode);
+ if (status == PR_FAILURE) {
+ fprintf(stderr, "PR_WaitProcess failed\n");
+ exit(1);
+ }
+ if (exitCode == 0) {
+ printf("PASS\n");
+ return 0;
+ } else {
+ printf("FAIL\n");
+ return 1;
+ }
+}
diff --git a/nsprpub/pr/tests/pipeping2.c b/nsprpub/pr/tests/pipeping2.c
new file mode 100644
index 0000000000..ed96109172
--- /dev/null
+++ b/nsprpub/pr/tests/pipeping2.c
@@ -0,0 +1,160 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * File: pipeping2.c
+ *
+ * Description:
+ * This test runs in conjunction with the pipepong2 test.
+ * This test creates two pipes and passes two pipe fd's
+ * to the pipepong2 test. Then this test writes "ping" to
+ * to the pipepong2 test and the pipepong2 test writes "pong"
+ * back. To run this pair of tests, just invoke pipeping2.
+ *
+ * Tested areas: process creation, pipes, file descriptor
+ * inheritance.
+ */
+
+#include "prerror.h"
+#include "prio.h"
+#include "prproces.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#define NUM_ITERATIONS 10
+
+static char *child_argv[] = { "pipepong2", NULL };
+
+int main(int argc, char **argv)
+{
+ PRFileDesc *in_pipe[2];
+ PRFileDesc *out_pipe[2];
+ PRStatus status;
+ PRProcess *process;
+ PRProcessAttr *attr;
+ char buf[1024];
+ PRInt32 nBytes;
+ PRInt32 exitCode;
+ int idx;
+
+ status = PR_CreatePipe(&in_pipe[0], &in_pipe[1]);
+ if (status == PR_FAILURE) {
+ fprintf(stderr, "PR_CreatePipe failed\n");
+ exit(1);
+ }
+ status = PR_CreatePipe(&out_pipe[0], &out_pipe[1]);
+ if (status == PR_FAILURE) {
+ fprintf(stderr, "PR_CreatePipe failed\n");
+ exit(1);
+ }
+
+ status = PR_SetFDInheritable(in_pipe[0], PR_FALSE);
+ if (status == PR_FAILURE) {
+ fprintf(stderr, "PR_SetFDInheritable failed\n");
+ exit(1);
+ }
+ status = PR_SetFDInheritable(in_pipe[1], PR_TRUE);
+ if (status == PR_FAILURE) {
+ fprintf(stderr, "PR_SetFDInheritable failed\n");
+ exit(1);
+ }
+ status = PR_SetFDInheritable(out_pipe[0], PR_TRUE);
+ if (status == PR_FAILURE) {
+ fprintf(stderr, "PR_SetFDInheritable failed\n");
+ exit(1);
+ }
+ status = PR_SetFDInheritable(out_pipe[1], PR_FALSE);
+ if (status == PR_FAILURE) {
+ fprintf(stderr, "PR_SetFDInheritable failed\n");
+ exit(1);
+ }
+
+ attr = PR_NewProcessAttr();
+ if (attr == NULL) {
+ fprintf(stderr, "PR_NewProcessAttr failed\n");
+ exit(1);
+ }
+
+ status = PR_ProcessAttrSetInheritableFD(attr, out_pipe[0], "PIPE_READ");
+ if (status == PR_FAILURE) {
+ fprintf(stderr, "PR_ProcessAttrSetInheritableFD failed\n");
+ exit(1);
+ }
+ status = PR_ProcessAttrSetInheritableFD(attr, in_pipe[1], "PIPE_WRITE");
+ if (status == PR_FAILURE) {
+ fprintf(stderr, "PR_ProcessAttrSetInheritableFD failed\n");
+ exit(1);
+ }
+
+ process = PR_CreateProcess(child_argv[0], child_argv, NULL, attr);
+ if (process == NULL) {
+ fprintf(stderr, "PR_CreateProcess failed\n");
+ exit(1);
+ }
+ PR_DestroyProcessAttr(attr);
+ status = PR_Close(out_pipe[0]);
+ if (status == PR_FAILURE) {
+ fprintf(stderr, "PR_Close failed\n");
+ exit(1);
+ }
+ status = PR_Close(in_pipe[1]);
+ if (status == PR_FAILURE) {
+ fprintf(stderr, "PR_Close failed\n");
+ exit(1);
+ }
+
+ for (idx = 0; idx < NUM_ITERATIONS; idx++) {
+ strcpy(buf, "ping");
+ printf("ping process: sending \"%s\"\n", buf);
+ nBytes = PR_Write(out_pipe[1], buf, 5);
+ if (nBytes == -1) {
+ fprintf(stderr, "PR_Write failed: (%d, %d)\n",
+ PR_GetError(), PR_GetOSError());
+ exit(1);
+ }
+ memset(buf, 0, sizeof(buf));
+ nBytes = PR_Read(in_pipe[0], buf, sizeof(buf));
+ if (nBytes == -1) {
+ fprintf(stderr, "PR_Read failed\n");
+ exit(1);
+ }
+ printf("ping process: received \"%s\"\n", buf);
+ if (nBytes != 5) {
+ fprintf(stderr, "ping process: expected 5 bytes but got %d bytes\n",
+ nBytes);
+ exit(1);
+ }
+ if (strcmp(buf, "pong") != 0) {
+ fprintf(stderr, "ping process: expected \"pong\" but got \"%s\"\n",
+ buf);
+ exit(1);
+ }
+ }
+
+ status = PR_Close(in_pipe[0]);
+ if (status == PR_FAILURE) {
+ fprintf(stderr, "PR_Close failed\n");
+ exit(1);
+ }
+ status = PR_Close(out_pipe[1]);
+ if (status == PR_FAILURE) {
+ fprintf(stderr, "PR_Close failed\n");
+ exit(1);
+ }
+ status = PR_WaitProcess(process, &exitCode);
+ if (status == PR_FAILURE) {
+ fprintf(stderr, "PR_WaitProcess failed\n");
+ exit(1);
+ }
+ if (exitCode == 0) {
+ printf("PASS\n");
+ return 0;
+ } else {
+ printf("FAIL\n");
+ return 1;
+ }
+}
diff --git a/nsprpub/pr/tests/pipepong.c b/nsprpub/pr/tests/pipepong.c
new file mode 100644
index 0000000000..965aec32de
--- /dev/null
+++ b/nsprpub/pr/tests/pipepong.c
@@ -0,0 +1,60 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * File: pipepong.c
+ *
+ * Description:
+ * This test runs in conjunction with the pipeping test.
+ * The pipeping test creates two pipes and redirects the
+ * stdin and stdout of this test to the pipes. Then the
+ * pipeping test writes "ping" to this test and this test
+ * writes "pong" back. Note that this test does not depend
+ * on NSPR at all. To run this pair of tests, just invoke
+ * pipeping.
+ *
+ * Tested areas: process creation, pipes, file descriptor
+ * inheritance, standard I/O redirection.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#define NUM_ITERATIONS 10
+
+int main(int argc, char **argv)
+{
+ char buf[1024];
+ size_t nBytes;
+ int idx;
+
+ for (idx = 0; idx < NUM_ITERATIONS; idx++) {
+ memset(buf, 0, sizeof(buf));
+ nBytes = fread(buf, 1, 5, stdin);
+ fprintf(stderr, "pong process: received \"%s\"\n", buf);
+ if (nBytes != 5) {
+ fprintf(stderr, "pong process: expected 5 bytes but got %d bytes\n",
+ nBytes);
+ exit(1);
+ }
+ if (strcmp(buf, "ping") != 0) {
+ fprintf(stderr, "pong process: expected \"ping\" but got \"%s\"\n",
+ buf);
+ exit(1);
+ }
+
+ strcpy(buf, "pong");
+ fprintf(stderr, "pong process: sending \"%s\"\n", buf);
+ nBytes = fwrite(buf, 1, 5, stdout);
+ if (nBytes != 5) {
+ fprintf(stderr, "pong process: fwrite failed\n");
+ exit(1);
+ }
+ fflush(stdout);
+ }
+
+ return 0;
+}
diff --git a/nsprpub/pr/tests/pipepong2.c b/nsprpub/pr/tests/pipepong2.c
new file mode 100644
index 0000000000..839f252a08
--- /dev/null
+++ b/nsprpub/pr/tests/pipepong2.c
@@ -0,0 +1,98 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * File: pipepong2.c
+ *
+ * Description:
+ * This test runs in conjunction with the pipeping2 test.
+ * The pipeping2 test creates two pipes and passes two
+ * pipe fd's to this test. Then the pipeping2 test writes
+ * "ping" to this test and this test writes "pong" back.
+ * To run this pair of tests, just invoke pipeping2.
+ *
+ * Tested areas: process creation, pipes, file descriptor
+ * inheritance.
+ */
+
+#include "prerror.h"
+#include "prio.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#define NUM_ITERATIONS 10
+
+int main(int argc, char **argv)
+{
+ PRFileDesc *pipe_read, *pipe_write;
+ PRStatus status;
+ char buf[1024];
+ PRInt32 nBytes;
+ int idx;
+
+ pipe_read = PR_GetInheritedFD("PIPE_READ");
+ if (pipe_read == NULL) {
+ fprintf(stderr, "PR_GetInheritedFD failed\n");
+ exit(1);
+ }
+ status = PR_SetFDInheritable(pipe_read, PR_FALSE);
+ if (status == PR_FAILURE) {
+ fprintf(stderr, "PR_SetFDInheritable failed\n");
+ exit(1);
+ }
+ pipe_write = PR_GetInheritedFD("PIPE_WRITE");
+ if (pipe_write == NULL) {
+ fprintf(stderr, "PR_GetInheritedFD failed\n");
+ exit(1);
+ }
+ status = PR_SetFDInheritable(pipe_write, PR_FALSE);
+ if (status == PR_FAILURE) {
+ fprintf(stderr, "PR_SetFDInheritable failed\n");
+ exit(1);
+ }
+
+ for (idx = 0; idx < NUM_ITERATIONS; idx++) {
+ memset(buf, 0, sizeof(buf));
+ nBytes = PR_Read(pipe_read, buf, sizeof(buf));
+ if (nBytes == -1) {
+ fprintf(stderr, "PR_Read failed: (%d, %d)\n",
+ PR_GetError(), PR_GetOSError());
+ exit(1);
+ }
+ printf("pong process: received \"%s\"\n", buf);
+ if (nBytes != 5) {
+ fprintf(stderr, "pong process: expected 5 bytes but got %d bytes\n",
+ nBytes);
+ exit(1);
+ }
+ if (strcmp(buf, "ping") != 0) {
+ fprintf(stderr, "pong process: expected \"ping\" but got \"%s\"\n",
+ buf);
+ exit(1);
+ }
+
+ strcpy(buf, "pong");
+ printf("pong process: sending \"%s\"\n", buf);
+ nBytes = PR_Write(pipe_write, buf, 5);
+ if (nBytes == -1) {
+ fprintf(stderr, "PR_Write failed\n");
+ exit(1);
+ }
+ }
+
+ status = PR_Close(pipe_read);
+ if (status == PR_FAILURE) {
+ fprintf(stderr, "PR_Close failed\n");
+ exit(1);
+ }
+ status = PR_Close(pipe_write);
+ if (status == PR_FAILURE) {
+ fprintf(stderr, "PR_Close failed\n");
+ exit(1);
+ }
+ return 0;
+}
diff --git a/nsprpub/pr/tests/pipeself.c b/nsprpub/pr/tests/pipeself.c
new file mode 100644
index 0000000000..7066c58d1c
--- /dev/null
+++ b/nsprpub/pr/tests/pipeself.c
@@ -0,0 +1,228 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * File: pipeself.c
+ *
+ * Description:
+ * This test has two threads communicating with each other using
+ * two unidirectional pipes. The primordial thread is the ping
+ * thread and the other thread is the pong thread. The ping
+ * thread writes "ping" to the pong thread and the pong thread
+ * writes "pong" back.
+ */
+
+#include "prio.h"
+#include "prerror.h"
+#include "prthread.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define NUM_ITERATIONS 10
+
+static PRFileDesc *ping_in, *ping_out;
+static PRFileDesc *pong_in, *pong_out;
+
+static void PongThreadFunc(void *arg)
+{
+ char buf[1024];
+ int idx;
+ PRInt32 nBytes;
+ PRStatus status;
+
+ for (idx = 0; idx < NUM_ITERATIONS; idx++) {
+ memset(buf, 0, sizeof(buf));
+ nBytes = PR_Read(pong_in, buf, sizeof(buf));
+ if (nBytes == -1) {
+ fprintf(stderr, "PR_Read failed\n");
+ exit(1);
+ }
+ printf("pong thread: received \"%s\"\n", buf);
+ if (nBytes != 5) {
+ fprintf(stderr, "pong thread: expected 5 bytes but got %d bytes\n",
+ nBytes);
+ exit(1);
+ }
+ if (strcmp(buf, "ping") != 0) {
+ fprintf(stderr, "pong thread: expected \"ping\" but got \"%s\"\n",
+ buf);
+ exit(1);
+ }
+ strcpy(buf, "pong");
+ printf("pong thread: sending \"%s\"\n", buf);
+ nBytes = PR_Write(pong_out, buf, 5);
+ if (nBytes == -1) {
+ fprintf(stderr, "PR_Write failed: (%d, %d)\n", PR_GetError(),
+ PR_GetOSError());
+ exit(1);
+ }
+ }
+
+ status = PR_Close(pong_in);
+ if (status == PR_FAILURE) {
+ fprintf(stderr, "PR_Close failed\n");
+ exit(1);
+ }
+ status = PR_Close(pong_out);
+ if (status == PR_FAILURE) {
+ fprintf(stderr, "PR_Close failed\n");
+ exit(1);
+ }
+}
+
+int main(int argc, char **argv)
+{
+ PRStatus status;
+ PRThread *pongThread;
+ char buf[1024];
+ PRInt32 nBytes;
+ int idx;
+
+ status = PR_CreatePipe(&ping_in, &pong_out);
+ if (status == PR_FAILURE) {
+ fprintf(stderr, "PR_CreatePipe failed\n");
+ exit(1);
+ }
+ status = PR_CreatePipe(&pong_in, &ping_out);
+ if (status == PR_FAILURE) {
+ fprintf(stderr, "PR_CreatePipe failed\n");
+ exit(1);
+ }
+
+ pongThread = PR_CreateThread(PR_USER_THREAD, PongThreadFunc, NULL,
+ PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0);
+ if (pongThread == NULL) {
+ fprintf(stderr, "PR_CreateThread failed\n");
+ exit(1);
+ }
+
+ for (idx = 0; idx < NUM_ITERATIONS; idx++) {
+ strcpy(buf, "ping");
+ printf("ping thread: sending \"%s\"\n", buf);
+ nBytes = PR_Write(ping_out, buf, 5);
+ if (nBytes == -1) {
+ fprintf(stderr, "PR_Write failed: (%d, %d)\n", PR_GetError(),
+ PR_GetOSError());
+ exit(1);
+ }
+ memset(buf, 0, sizeof(buf));
+ nBytes = PR_Read(ping_in, buf, sizeof(buf));
+ if (nBytes == -1) {
+ fprintf(stderr, "PR_Read failed\n");
+ exit(1);
+ }
+ printf("ping thread: received \"%s\"\n", buf);
+ if (nBytes != 5) {
+ fprintf(stderr, "ping thread: expected 5 bytes but got %d bytes\n",
+ nBytes);
+ exit(1);
+ }
+ if (strcmp(buf, "pong") != 0) {
+ fprintf(stderr, "ping thread: expected \"pong\" but got \"%s\"\n",
+ buf);
+ exit(1);
+ }
+ }
+
+ status = PR_Close(ping_in);
+ if (status == PR_FAILURE) {
+ fprintf(stderr, "PR_Close failed\n");
+ exit(1);
+ }
+ status = PR_Close(ping_out);
+ if (status == PR_FAILURE) {
+ fprintf(stderr, "PR_Close failed\n");
+ exit(1);
+ }
+ status = PR_JoinThread(pongThread);
+ if (status == PR_FAILURE) {
+ fprintf(stderr, "PR_JoinThread failed\n");
+ exit(1);
+ }
+
+#if defined(XP_UNIX)
+ /*
+ * Test PR_Available for pipes
+ */
+ status = PR_CreatePipe(&ping_in, &ping_out);
+ if (status == PR_FAILURE) {
+ fprintf(stderr, "PR_CreatePipe failed\n");
+ exit(1);
+ }
+ nBytes = PR_Write(ping_out, buf, 250);
+ if (nBytes == -1) {
+ fprintf(stderr, "PR_Write failed: (%d, %d)\n", PR_GetError(),
+ PR_GetOSError());
+ exit(1);
+ }
+ nBytes = PR_Available(ping_in);
+ if (nBytes < 0) {
+ fprintf(stderr, "PR_Available failed: (%d, %d)\n", PR_GetError(),
+ PR_GetOSError());
+ exit(1);
+ } else if (nBytes != 250) {
+ fprintf(stderr, "PR_Available: expected 250 bytes but got %d bytes\n",
+ nBytes);
+ exit(1);
+ }
+ printf("PR_Available: expected %d, got %d bytes\n",250, nBytes);
+ /* read some data */
+ nBytes = PR_Read(ping_in, buf, 7);
+ if (nBytes == -1) {
+ fprintf(stderr, "PR_Read failed\n");
+ exit(1);
+ }
+ /* check available data */
+ nBytes = PR_Available(ping_in);
+ if (nBytes < 0) {
+ fprintf(stderr, "PR_Available failed: (%d, %d)\n", PR_GetError(),
+ PR_GetOSError());
+ exit(1);
+ } else if (nBytes != (250 - 7)) {
+ fprintf(stderr, "PR_Available: expected 243 bytes but got %d bytes\n",
+ nBytes);
+ exit(1);
+ }
+ printf("PR_Available: expected %d, got %d bytes\n",243, nBytes);
+ /* read all data */
+ nBytes = PR_Read(ping_in, buf, sizeof(buf));
+ if (nBytes == -1) {
+ fprintf(stderr, "PR_Read failed\n");
+ exit(1);
+ } else if (nBytes != 243) {
+ fprintf(stderr, "PR_Read failed: expected %d, got %d bytes\n",
+ 243, nBytes);
+ exit(1);
+ }
+ /* check available data */
+ nBytes = PR_Available(ping_in);
+ if (nBytes < 0) {
+ fprintf(stderr, "PR_Available failed: (%d, %d)\n", PR_GetError(),
+ PR_GetOSError());
+ exit(1);
+ } else if (nBytes != 0) {
+ fprintf(stderr, "PR_Available: expected 0 bytes but got %d bytes\n",
+ nBytes);
+ exit(1);
+ }
+ printf("PR_Available: expected %d, got %d bytes\n", 0, nBytes);
+
+ status = PR_Close(ping_in);
+ if (status == PR_FAILURE) {
+ fprintf(stderr, "PR_Close failed\n");
+ exit(1);
+ }
+ status = PR_Close(ping_out);
+ if (status == PR_FAILURE) {
+ fprintf(stderr, "PR_Close failed\n");
+ exit(1);
+ }
+#endif /* XP_UNIX */
+
+ printf("PASS\n");
+ return 0;
+}
diff --git a/nsprpub/pr/tests/poll_er.c b/nsprpub/pr/tests/poll_er.c
new file mode 100644
index 0000000000..b3a751d83e
--- /dev/null
+++ b/nsprpub/pr/tests/poll_er.c
@@ -0,0 +1,210 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/***********************************************************************
+**
+** Name: prpoll_err.c
+**
+** Description: This program tests PR_Poll with sockets.
+** error reporting operation is tested
+**
+** Modification History:
+** 19-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
+** The debug mode will print all of the printfs associated with this test.
+** The regress mode will be the default mode. Since the regress tool limits
+** the output to a one line status:PASS or FAIL,all of the printf statements
+** have been handled with an if (debug_mode) statement.
+** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to
+** recognize the return code from tha main program.
+***********************************************************************/
+
+/***********************************************************************
+** Includes
+***********************************************************************/
+/* Used to get the command line option */
+#include "plgetopt.h"
+
+#include "primpl.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+PRIntn failed_already=0;
+PRIntn debug_mode;
+
+static void
+ClientThreadFunc(void *arg)
+{
+ PRFileDesc *badFD = (PRFileDesc *) arg;
+ /*
+ * Make the fd invalid
+ */
+#if defined(XP_UNIX)
+ close(PR_FileDesc2NativeHandle(badFD));
+#elif defined(XP_OS2)
+ soclose(PR_FileDesc2NativeHandle(badFD));
+#elif defined(WIN32) || defined(WIN16)
+ closesocket(PR_FileDesc2NativeHandle(badFD));
+#else
+#error "Unknown architecture"
+#endif
+}
+
+int main(int argc, char **argv)
+{
+ PRFileDesc *listenSock1, *listenSock2;
+ PRFileDesc *badFD;
+ PRUint16 listenPort1, listenPort2;
+ PRNetAddr addr;
+ char buf[128];
+ PRPollDesc pds0[10], pds1[10], *pds, *other_pds;
+ PRIntn npds;
+ PRInt32 retVal;
+
+ /* The command line argument: -d is used to determine if the test is being run
+ in debug mode. The regress tool requires only one line output:PASS or FAIL.
+ All of the printfs associated with this test has been handled with a if (debug_mode)
+ test.
+ Usage: test_name -d
+ */
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "d:");
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 'd': /* debug mode */
+ debug_mode = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ /* main test */
+
+ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
+ PR_STDIO_INIT();
+
+ if (debug_mode) {
+ printf("This program tests PR_Poll with sockets.\n");
+ printf("error reporting is tested.\n\n");
+ }
+
+ /* Create two listening sockets */
+ if ((listenSock1 = PR_NewTCPSocket()) == NULL) {
+ fprintf(stderr, "Can't create a new TCP socket\n");
+ failed_already=1;
+ goto exit_now;
+ }
+ addr.inet.family = AF_INET;
+ addr.inet.ip = PR_htonl(INADDR_ANY);
+ addr.inet.port = PR_htons(0);
+ if (PR_Bind(listenSock1, &addr) == PR_FAILURE) {
+ fprintf(stderr, "Can't bind socket\n");
+ failed_already=1;
+ goto exit_now;
+ }
+ if (PR_GetSockName(listenSock1, &addr) == PR_FAILURE) {
+ fprintf(stderr, "PR_GetSockName failed\n");
+ failed_already=1;
+ goto exit_now;
+ }
+ listenPort1 = PR_ntohs(addr.inet.port);
+ if (PR_Listen(listenSock1, 5) == PR_FAILURE) {
+ fprintf(stderr, "Can't listen on a socket\n");
+ failed_already=1;
+ goto exit_now;
+ }
+
+ if ((listenSock2 = PR_NewTCPSocket()) == NULL) {
+ fprintf(stderr, "Can't create a new TCP socket\n");
+ failed_already=1;
+ goto exit_now;
+ }
+ addr.inet.family = AF_INET;
+ addr.inet.ip = PR_htonl(INADDR_ANY);
+ addr.inet.port = PR_htons(0);
+ if (PR_Bind(listenSock2, &addr) == PR_FAILURE) {
+ fprintf(stderr, "Can't bind socket\n");
+ failed_already=1;
+ goto exit_now;
+ }
+ if (PR_GetSockName(listenSock2, &addr) == PR_FAILURE) {
+ fprintf(stderr, "PR_GetSockName failed\n");
+ failed_already=1;
+ goto exit_now;
+ }
+ listenPort2 = PR_ntohs(addr.inet.port);
+ if (PR_Listen(listenSock2, 5) == PR_FAILURE) {
+ fprintf(stderr, "Can't listen on a socket\n");
+ failed_already=1;
+ goto exit_now;
+ }
+ PR_snprintf(buf, sizeof(buf),
+ "The server thread is listening on ports %hu and %hu\n\n",
+ listenPort1, listenPort2);
+ if (debug_mode) {
+ printf("%s", buf);
+ }
+
+ /* Set up the poll descriptor array */
+ pds = pds0;
+ other_pds = pds1;
+ memset(pds, 0, sizeof(pds));
+ pds[0].fd = listenSock1;
+ pds[0].in_flags = PR_POLL_READ;
+ pds[1].fd = listenSock2;
+ pds[1].in_flags = PR_POLL_READ;
+ npds = 2;
+
+
+ /* Testing bad fd */
+ if (debug_mode) {
+ printf("PR_Poll should detect a bad file descriptor\n");
+ }
+ if ((badFD = PR_NewTCPSocket()) == NULL) {
+ fprintf(stderr, "Can't create a TCP socket\n");
+ goto exit_now;
+ }
+
+ pds[2].fd = badFD;
+ pds[2].in_flags = PR_POLL_READ;
+ npds = 3;
+
+ if (PR_CreateThread(PR_USER_THREAD, ClientThreadFunc,
+ badFD, PR_PRIORITY_NORMAL, PR_LOCAL_THREAD,
+ PR_UNJOINABLE_THREAD, 0) == NULL) {
+ fprintf(stderr, "cannot create thread\n");
+ exit(1);
+ }
+
+ retVal = PR_Poll(pds, npds, PR_INTERVAL_NO_TIMEOUT);
+ if (retVal != 1 || (unsigned short) pds[2].out_flags != PR_POLL_NVAL) {
+ fprintf(stderr, "Failed to detect the bad fd: "
+ "PR_Poll returns %d, out_flags is 0x%hx\n",
+ retVal, pds[2].out_flags);
+ failed_already=1;
+ goto exit_now;
+ }
+ if (debug_mode) {
+ printf("PR_Poll detected the bad fd. Test passed.\n\n");
+ }
+ PR_Cleanup();
+ goto exit_now;
+exit_now:
+ if(failed_already) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+}
+
diff --git a/nsprpub/pr/tests/poll_nm.c b/nsprpub/pr/tests/poll_nm.c
new file mode 100644
index 0000000000..f356d141ac
--- /dev/null
+++ b/nsprpub/pr/tests/poll_nm.c
@@ -0,0 +1,355 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/***********************************************************************
+**
+** Name: prpoll_norm.c
+**
+** Description: This program tests PR_Poll with sockets.
+** Normal operation are tested
+**
+** Modification History:
+** 19-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
+** The debug mode will print all of the printfs associated with this test.
+** The regress mode will be the default mode. Since the regress tool limits
+** the output to a one line status:PASS or FAIL,all of the printf statements
+** have been handled with an if (debug_mode) statement.
+** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to
+** recognize the return code from tha main program.
+***********************************************************************/
+
+/***********************************************************************
+** Includes
+***********************************************************************/
+/* Used to get the command line option */
+#include "plgetopt.h"
+
+#include "prinit.h"
+#include "prio.h"
+#include "prlog.h"
+#include "prprf.h"
+#include "prnetdb.h"
+#include "obsolete/probslet.h"
+
+#include "private/pprio.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+PRIntn failed_already=0;
+PRIntn debug_mode;
+
+#define NUM_ITERATIONS 5
+
+static void PR_CALLBACK
+clientThreadFunc(void *arg)
+{
+ PRUintn port = (PRUintn) arg;
+ PRFileDesc *sock;
+ PRNetAddr addr;
+ char buf[128];
+ int i;
+ PRStatus sts;
+ PRInt32 n;
+
+ addr.inet.family = PR_AF_INET;
+ addr.inet.port = PR_htons((PRUint16)port);
+ addr.inet.ip = PR_htonl(PR_INADDR_LOOPBACK);
+ memset(buf, 0, sizeof(buf));
+ PR_snprintf(buf, sizeof(buf), "%hu", port);
+
+ for (i = 0; i < NUM_ITERATIONS; i++) {
+ sock = PR_NewTCPSocket();
+ PR_ASSERT(sock != NULL);
+
+ sts = PR_Connect(sock, &addr, PR_INTERVAL_NO_TIMEOUT);
+ PR_ASSERT(sts == PR_SUCCESS);
+
+ n = PR_Write(sock, buf, sizeof(buf));
+ PR_ASSERT(n >= 0);
+
+ sts = PR_Close(sock);
+ PR_ASSERT(sts == PR_SUCCESS);
+ }
+}
+
+int main(int argc, char **argv)
+{
+ PRFileDesc *listenSock1 = NULL, *listenSock2 = NULL;
+ PRUint16 listenPort1, listenPort2;
+ PRNetAddr addr;
+ char buf[128];
+ PRThread *clientThread;
+ PRPollDesc pds0[20], pds1[20], *pds, *other_pds;
+ PRIntn npds;
+ PRInt32 retVal;
+ PRIntn i, j;
+ PRSocketOptionData optval;
+
+ /* The command line argument: -d is used to determine if the test is being run
+ in debug mode. The regress tool requires only one line output:PASS or FAIL.
+ All of the printfs associated with this test has been handled with a if (debug_mode)
+ test.
+ Usage: test_name -d
+ */
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "d:");
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 'd': /* debug mode */
+ debug_mode = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ /* main test */
+
+ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
+ PR_STDIO_INIT();
+
+ if (debug_mode) {
+ printf("This program tests PR_Poll with sockets.\n");
+ printf("Normal operation are tested.\n\n");
+ }
+
+ /* Create two listening sockets */
+ if ((listenSock1 = PR_NewTCPSocket()) == NULL) {
+ fprintf(stderr, "Can't create a new TCP socket\n");
+ failed_already=1;
+ goto exit_now;
+ }
+ memset(&addr, 0, sizeof(addr));
+ addr.inet.family = PR_AF_INET;
+ addr.inet.ip = PR_htonl(PR_INADDR_ANY);
+ addr.inet.port = PR_htons(0);
+ if (PR_Bind(listenSock1, &addr) == PR_FAILURE) {
+ fprintf(stderr, "Can't bind socket\n");
+ failed_already=1;
+ goto exit_now;
+ }
+ if (PR_GetSockName(listenSock1, &addr) == PR_FAILURE) {
+ fprintf(stderr, "PR_GetSockName failed\n");
+ failed_already=1;
+ goto exit_now;
+ }
+ listenPort1 = PR_ntohs(addr.inet.port);
+ optval.option = PR_SockOpt_Nonblocking;
+ optval.value.non_blocking = PR_TRUE;
+ PR_SetSocketOption(listenSock1, &optval);
+ if (PR_Listen(listenSock1, 5) == PR_FAILURE) {
+ fprintf(stderr, "Can't listen on a socket\n");
+ failed_already=1;
+ goto exit_now;
+ }
+
+ if ((listenSock2 = PR_NewTCPSocket()) == NULL) {
+ fprintf(stderr, "Can't create a new TCP socket\n");
+ failed_already=1;
+ goto exit_now;
+ }
+ addr.inet.family = PR_AF_INET;
+ addr.inet.ip = PR_htonl(PR_INADDR_ANY);
+ addr.inet.port = PR_htons(0);
+ if (PR_Bind(listenSock2, &addr) == PR_FAILURE) {
+ fprintf(stderr, "Can't bind socket\n");
+ failed_already=1;
+ goto exit_now;
+ }
+ if (PR_GetSockName(listenSock2, &addr) == PR_FAILURE) {
+ fprintf(stderr, "PR_GetSockName failed\n");
+ failed_already=1;
+ goto exit_now;
+ }
+ listenPort2 = PR_ntohs(addr.inet.port);
+ PR_SetSocketOption(listenSock2, &optval);
+ if (PR_Listen(listenSock2, 5) == PR_FAILURE) {
+ fprintf(stderr, "Can't listen on a socket\n");
+ failed_already=1;
+ goto exit_now;
+ }
+ PR_snprintf(buf, sizeof(buf),
+ "The server thread is listening on ports %hu and %hu\n\n",
+ listenPort1, listenPort2);
+ if (debug_mode) {
+ printf("%s", buf);
+ }
+
+ /* Set up the poll descriptor array */
+ pds = pds0;
+ other_pds = pds1;
+ memset(pds, 0, sizeof(pds));
+ pds[0].fd = listenSock1;
+ pds[0].in_flags = PR_POLL_READ;
+ pds[1].fd = listenSock2;
+ pds[1].in_flags = PR_POLL_READ;
+ /* Add some unused entries to test if they are ignored by PR_Poll() */
+ memset(&pds[2], 0, sizeof(pds[2]));
+ memset(&pds[3], 0, sizeof(pds[3]));
+ memset(&pds[4], 0, sizeof(pds[4]));
+ npds = 5;
+
+ clientThread = PR_CreateThread(PR_USER_THREAD,
+ clientThreadFunc, (void *) listenPort1,
+ PR_PRIORITY_NORMAL, PR_LOCAL_THREAD,
+ PR_UNJOINABLE_THREAD, 0);
+ if (clientThread == NULL) {
+ fprintf(stderr, "can't create thread\n");
+ failed_already=1;
+ goto exit_now;
+ }
+
+ clientThread = PR_CreateThread(PR_USER_THREAD,
+ clientThreadFunc, (void *) listenPort2,
+ PR_PRIORITY_NORMAL, PR_LOCAL_THREAD,
+ PR_UNJOINABLE_THREAD, 0);
+ if (clientThread == NULL) {
+ fprintf(stderr, "can't create thread\n");
+ failed_already=1;
+ goto exit_now;
+ }
+
+ if (debug_mode) {
+ printf("Two client threads are created. Each of them will\n");
+ printf("send data to one of the two ports the server is listening on.\n");
+ printf("The data they send is the port number. Each of them send\n");
+ printf("the data five times, so you should see ten lines below,\n");
+ printf("interleaved in an arbitrary order.\n");
+ }
+
+ /* two clients, three events per iteration: accept, read, close */
+ i = 0;
+ while (i < 2 * 3 * NUM_ITERATIONS) {
+ PRPollDesc *tmp;
+ int nextIndex;
+ int nEvents = 0;
+
+ retVal = PR_Poll(pds, npds, PR_INTERVAL_NO_TIMEOUT);
+ PR_ASSERT(retVal != 0); /* no timeout */
+ if (retVal == -1) {
+ fprintf(stderr, "PR_Poll failed\n");
+ failed_already=1;
+ goto exit_now;
+ }
+
+ nextIndex = 2;
+ /* the two listening sockets */
+ for (j = 0; j < 2; j++) {
+ other_pds[j] = pds[j];
+ PR_ASSERT((pds[j].out_flags & PR_POLL_WRITE) == 0
+ && (pds[j].out_flags & PR_POLL_EXCEPT) == 0);
+ if (pds[j].out_flags & PR_POLL_READ) {
+ PRFileDesc *sock;
+
+ nEvents++;
+ sock = PR_Accept(pds[j].fd, NULL, PR_INTERVAL_NO_TIMEOUT);
+ if (sock == NULL) {
+ fprintf(stderr, "PR_Accept() failed\n");
+ failed_already=1;
+ goto exit_now;
+ }
+ other_pds[nextIndex].fd = sock;
+ other_pds[nextIndex].in_flags = PR_POLL_READ;
+ nextIndex++;
+ } else if (pds[j].out_flags & PR_POLL_ERR) {
+ fprintf(stderr, "PR_Poll() indicates that an fd has error\n");
+ failed_already=1;
+ goto exit_now;
+ } else if (pds[j].out_flags & PR_POLL_NVAL) {
+ fprintf(stderr, "PR_Poll() indicates that fd %d is invalid\n",
+ PR_FileDesc2NativeHandle(pds[j].fd));
+ failed_already=1;
+ goto exit_now;
+ }
+ }
+
+ for (j = 2; j < npds; j++) {
+ if (NULL == pds[j].fd) {
+ /*
+ * Keep the unused entries in the poll descriptor array
+ * for testing purposes.
+ */
+ other_pds[nextIndex] = pds[j];
+ nextIndex++;
+ continue;
+ }
+
+ PR_ASSERT((pds[j].out_flags & PR_POLL_WRITE) == 0
+ && (pds[j].out_flags & PR_POLL_EXCEPT) == 0);
+ if (pds[j].out_flags & PR_POLL_READ) {
+ PRInt32 nAvail;
+ PRInt32 nRead;
+
+ nEvents++;
+ nAvail = PR_Available(pds[j].fd);
+ nRead = PR_Read(pds[j].fd, buf, sizeof(buf));
+ PR_ASSERT(nAvail == nRead);
+ if (nRead == -1) {
+ fprintf(stderr, "PR_Read() failed\n");
+ failed_already=1;
+ goto exit_now;
+ } else if (nRead == 0) {
+ PR_Close(pds[j].fd);
+ continue;
+ } else {
+ /* Just to be safe */
+ buf[127] = '\0';
+ if (debug_mode) {
+ printf("The server received \"%s\" from a client\n", buf);
+ }
+ }
+ } else if (pds[j].out_flags & PR_POLL_ERR) {
+ fprintf(stderr, "PR_Poll() indicates that an fd has error\n");
+ failed_already=1;
+ goto exit_now;
+ } else if (pds[j].out_flags & PR_POLL_NVAL) {
+ fprintf(stderr, "PR_Poll() indicates that an fd is invalid\n");
+ failed_already=1;
+ goto exit_now;
+ }
+ other_pds[nextIndex] = pds[j];
+ nextIndex++;
+ }
+
+ PR_ASSERT(retVal == nEvents);
+ /* swap */
+ tmp = pds;
+ pds = other_pds;
+ other_pds = tmp;
+ npds = nextIndex;
+ i += nEvents;
+ }
+
+ if (debug_mode) {
+ printf("Tests passed\n");
+ }
+
+exit_now:
+
+ if (listenSock1) {
+ PR_Close(listenSock1);
+ }
+ if (listenSock2) {
+ PR_Close(listenSock2);
+ }
+
+ PR_Cleanup();
+
+ if(failed_already) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+
+}
diff --git a/nsprpub/pr/tests/poll_to.c b/nsprpub/pr/tests/poll_to.c
new file mode 100644
index 0000000000..91291bcb11
--- /dev/null
+++ b/nsprpub/pr/tests/poll_to.c
@@ -0,0 +1,209 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/***********************************************************************
+**
+** Name: prpoll_to.c
+**
+** Description: This program tests PR_Poll with sockets.
+** Timeout operation is tested
+**
+** Modification History:
+** 14-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
+** The debug mode will print all of the printfs associated with this test.
+** The regress mode will be the default mode. Since the regress tool limits
+** the output to a one line status:PASS or FAIL,all of the printf statements
+** have been handled with an if (debug_mode) statement.
+** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to
+** recognize the return code from tha main program.
+***********************************************************************/
+
+/***********************************************************************
+** Includes
+***********************************************************************/
+/* Used to get the command line option */
+#include "plgetopt.h"
+
+#include "prinit.h"
+#include "prio.h"
+#include "prlog.h"
+#include "prprf.h"
+#include "prnetdb.h"
+
+#include "private/pprio.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+PRIntn failed_already=0;
+PRIntn debug_mode;
+
+int main(int argc, char **argv)
+{
+ PRFileDesc *listenSock1 = NULL, *listenSock2 = NULL;
+ PRUint16 listenPort1, listenPort2;
+ PRNetAddr addr;
+ char buf[128];
+ PRPollDesc pds0[10], pds1[10], *pds, *other_pds;
+ PRIntn npds;
+ PRInt32 retVal;
+
+ /* The command line argument: -d is used to determine if the test is being run
+ in debug mode. The regress tool requires only one line output:PASS or FAIL.
+ All of the printfs associated with this test has been handled with a if (debug_mode)
+ test.
+ Usage: test_name -d
+ */
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "d:");
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 'd': /* debug mode */
+ debug_mode = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ /* main test */
+
+ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
+ PR_STDIO_INIT();
+
+ if (debug_mode) {
+ printf("This program tests PR_Poll with sockets.\n");
+ printf("Timeout is tested.\n\n");
+ }
+
+ /* Create two listening sockets */
+ if ((listenSock1 = PR_NewTCPSocket()) == NULL) {
+ fprintf(stderr, "Can't create a new TCP socket\n");
+ if (!debug_mode) {
+ failed_already=1;
+ }
+ goto exit_now;
+ }
+ memset(&addr, 0, sizeof(addr));
+ addr.inet.family = PR_AF_INET;
+ addr.inet.ip = PR_htonl(PR_INADDR_ANY);
+ addr.inet.port = PR_htons(0);
+ if (PR_Bind(listenSock1, &addr) == PR_FAILURE) {
+ fprintf(stderr, "Can't bind socket\n");
+ if (!debug_mode) {
+ failed_already=1;
+ }
+ goto exit_now;
+ }
+ if (PR_GetSockName(listenSock1, &addr) == PR_FAILURE) {
+ fprintf(stderr, "PR_GetSockName failed\n");
+ if (!debug_mode) {
+ failed_already=1;
+ }
+ goto exit_now;
+ }
+ listenPort1 = PR_ntohs(addr.inet.port);
+ if (PR_Listen(listenSock1, 5) == PR_FAILURE) {
+ fprintf(stderr, "Can't listen on a socket\n");
+ if (!debug_mode) {
+ failed_already=1;
+ }
+ goto exit_now;
+ }
+
+ if ((listenSock2 = PR_NewTCPSocket()) == NULL) {
+ fprintf(stderr, "Can't create a new TCP socket\n");
+ if (!debug_mode) {
+ failed_already=1;
+ }
+ goto exit_now;
+ }
+ addr.inet.family = PR_AF_INET;
+ addr.inet.ip = PR_htonl(PR_INADDR_ANY);
+ addr.inet.port = PR_htons(0);
+ if (PR_Bind(listenSock2, &addr) == PR_FAILURE) {
+ fprintf(stderr, "Can't bind socket\n");
+ if (!debug_mode) {
+ failed_already=1;
+ }
+ goto exit_now;
+ }
+ if (PR_GetSockName(listenSock2, &addr) == PR_FAILURE) {
+ fprintf(stderr, "PR_GetSockName failed\n");
+ if (!debug_mode) {
+ failed_already=1;
+ }
+ goto exit_now;
+ }
+ listenPort2 = PR_ntohs(addr.inet.port);
+ if (PR_Listen(listenSock2, 5) == PR_FAILURE) {
+ fprintf(stderr, "Can't listen on a socket\n");
+ if (!debug_mode) {
+ failed_already=1;
+ }
+ goto exit_now;
+ }
+ PR_snprintf(buf, sizeof(buf),
+ "The server thread is listening on ports %hu and %hu\n\n",
+ listenPort1, listenPort2);
+ if (debug_mode) {
+ printf("%s", buf);
+ }
+
+ /* Set up the poll descriptor array */
+ pds = pds0;
+ other_pds = pds1;
+ memset(pds, 0, sizeof(pds));
+ pds[0].fd = listenSock1;
+ pds[0].in_flags = PR_POLL_READ;
+ pds[1].fd = listenSock2;
+ pds[1].in_flags = PR_POLL_READ;
+ npds = 2;
+
+ /* Testing timeout */
+ if (debug_mode) {
+ printf("PR_Poll should time out in 5 seconds\n");
+ }
+ retVal = PR_Poll(pds, npds, PR_SecondsToInterval(5));
+ if (retVal != 0) {
+ PR_snprintf(buf, sizeof(buf),
+ "PR_Poll should time out and return 0, but it returns %ld\n",
+ retVal);
+ fprintf(stderr, "%s", buf);
+ if (!debug_mode) {
+ failed_already=1;
+ }
+ goto exit_now;
+ }
+ if (debug_mode) {
+ printf("PR_Poll timed out. Test passed.\n\n");
+ }
+
+exit_now:
+
+ if (listenSock1) {
+ PR_Close(listenSock1);
+ }
+ if (listenSock2) {
+ PR_Close(listenSock2);
+ }
+
+ PR_Cleanup();
+
+ if(failed_already) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+
+}
diff --git a/nsprpub/pr/tests/pollable.c b/nsprpub/pr/tests/pollable.c
new file mode 100644
index 0000000000..7d0b51cac3
--- /dev/null
+++ b/nsprpub/pr/tests/pollable.c
@@ -0,0 +1,261 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * A test for the pollable events.
+ *
+ * A number of threads are in a ring configuration, each waiting on
+ * a pollable event that is set by its upstream neighbor.
+ */
+
+#include "prinit.h"
+#include "prio.h"
+#include "prthread.h"
+#include "prerror.h"
+#include "prmem.h"
+#include "prlog.h"
+#include "prprf.h"
+
+#include "plgetopt.h"
+
+#include <stdlib.h>
+
+#define DEFAULT_THREADS 10
+#define DEFAULT_LOOPS 100
+
+PRIntn numThreads = DEFAULT_THREADS;
+PRIntn numIterations = DEFAULT_LOOPS;
+PRIntervalTime dally = PR_INTERVAL_NO_WAIT;
+PRFileDesc *debug_out = NULL;
+PRBool debug_mode = PR_FALSE;
+PRBool verbosity = PR_FALSE;
+
+typedef struct ThreadData {
+ PRFileDesc *event;
+ int index;
+ struct ThreadData *next;
+} ThreadData;
+
+void ThreadRoutine(void *arg)
+{
+ ThreadData *data = (ThreadData *) arg;
+ PRIntn i;
+ PRPollDesc pd;
+ PRInt32 rv;
+
+ pd.fd = data->event;
+ pd.in_flags = PR_POLL_READ;
+
+ for (i = 0; i < numIterations; i++) {
+ rv = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT);
+ if (rv == -1) {
+ PR_fprintf(PR_STDERR, "PR_Poll failed\n");
+ exit(1);
+ }
+ if (verbosity) {
+ PR_fprintf(debug_out, "thread %d awakened\n", data->index);
+ }
+ PR_ASSERT(rv != 0);
+ PR_ASSERT(pd.out_flags & PR_POLL_READ);
+ if (PR_WaitForPollableEvent(data->event) == PR_FAILURE) {
+ PR_fprintf(PR_STDERR, "consume event failed\n");
+ exit(1);
+ }
+ if (dally != PR_INTERVAL_NO_WAIT) {
+ PR_Sleep(dally);
+ }
+ if (verbosity) {
+ PR_fprintf(debug_out, "thread %d posting event\n", data->index);
+ }
+ if (PR_SetPollableEvent(data->next->event) == PR_FAILURE) {
+ PR_fprintf(PR_STDERR, "post event failed\n");
+ exit(1);
+ }
+ }
+}
+
+static void Help(void)
+{
+ debug_out = PR_STDOUT;
+
+ PR_fprintf(
+ debug_out, "Usage: pollable [-c n] [-t n] [-d] [-v] [-G] [-C n] [-D n]\n");
+ PR_fprintf(
+ debug_out, "-c n\tloops at thread level (default: %d)\n", DEFAULT_LOOPS);
+ PR_fprintf(
+ debug_out, "-t n\tnumber of threads (default: %d)\n", DEFAULT_THREADS);
+ PR_fprintf(debug_out, "-d\tturn on debugging output (default: FALSE)\n");
+ PR_fprintf(debug_out, "-v\tturn on verbose output (default: FALSE)\n");
+ PR_fprintf(debug_out, "-G\tglobal threads only (default: FALSE)\n");
+ PR_fprintf(debug_out, "-C n\tconcurrency setting (default: 1)\n");
+ PR_fprintf(debug_out, "-D n\tdally setting (msecs) (default: 0)\n");
+} /* Help */
+
+int main(int argc, char **argv)
+{
+ ThreadData selfData;
+ ThreadData *data;
+ PRThread **thread;
+ void *block;
+ PRIntn i;
+ PRIntervalTime timeStart, timeEnd;
+ PRPollDesc pd;
+ PRInt32 rv;
+ PRThreadScope thread_scope = PR_LOCAL_THREAD;
+ PRBool help = PR_FALSE;
+ PRUintn concurrency = 1;
+ PRUintn average;
+ PLOptStatus os;
+ PLOptState *opt;
+
+ PR_STDIO_INIT();
+
+ opt = PL_CreateOptState(argc, argv, "hdvc:t:C:GD:");
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option) {
+ case 'v': /* verbose mode */
+ verbosity = PR_TRUE;
+ case 'd': /* debug mode */
+ debug_mode = PR_TRUE;
+ break;
+ case 'c': /* loop counter */
+ numIterations = atoi(opt->value);
+ break;
+ case 't': /* thread limit */
+ numThreads = atoi(opt->value);
+ break;
+ case 'C': /* Concurrency limit */
+ concurrency = atoi(opt->value);
+ break;
+ case 'G': /* global threads only */
+ thread_scope = PR_GLOBAL_THREAD;
+ break;
+ case 'D': /* dally */
+ dally = PR_MillisecondsToInterval(atoi(opt->value));
+ break;
+ case 'h': /* help message */
+ Help();
+ help = PR_TRUE;
+ break;
+ default:
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ if (help) {
+ return 1;
+ }
+
+ if (concurrency > 1) {
+ PR_SetConcurrency(concurrency);
+ }
+
+ if (PR_TRUE == debug_mode) {
+ debug_out = PR_STDOUT;
+ PR_fprintf(debug_out, "Test parameters\n");
+ PR_fprintf(debug_out, "\tThreads involved: %d\n", numThreads);
+ PR_fprintf(debug_out, "\tIteration limit: %d\n", numIterations);
+ PR_fprintf(debug_out, "\tConcurrency: %d\n", concurrency);
+ PR_fprintf(debug_out, "\tThread type: %s\n",
+ (PR_GLOBAL_THREAD == thread_scope) ? "GLOBAL" : "LOCAL");
+ }
+
+ /*
+ * Malloc a block of memory and divide it into data and thread.
+ */
+ block = PR_MALLOC(numThreads * (sizeof(ThreadData) + sizeof(PRThread *)));
+ if (block == NULL) {
+ PR_fprintf(PR_STDERR, "cannot malloc, failed\n");
+ exit(1);
+ }
+ data = (ThreadData *) block;
+ thread = (PRThread **) &data[numThreads];
+
+ /* Pollable event */
+ selfData.event = PR_NewPollableEvent();
+ if (selfData.event == NULL) {
+ PR_fprintf(PR_STDERR, "cannot create event: (%ld, %ld)\n",
+ PR_GetError(), PR_GetOSError());
+ exit(1);
+ }
+ selfData.next = &data[0];
+ for (i = 0; i < numThreads; i++) {
+ data[i].event = PR_NewPollableEvent();
+ if (data[i].event == NULL) {
+ PR_fprintf(PR_STDERR, "cannot create event: (%ld, %ld)\n",
+ PR_GetError(), PR_GetOSError());
+ exit(1);
+ }
+ data[i].index = i;
+ if (i != numThreads - 1) {
+ data[i].next = &data[i + 1];
+ } else {
+ data[i].next = &selfData;
+ }
+
+ thread[i] = PR_CreateThread(PR_USER_THREAD,
+ ThreadRoutine, &data[i], PR_PRIORITY_NORMAL,
+ thread_scope, PR_JOINABLE_THREAD, 0);
+ if (thread[i] == NULL) {
+ PR_fprintf(PR_STDERR, "cannot create thread\n");
+ exit(1);
+ }
+ }
+
+ timeStart = PR_IntervalNow();
+ pd.fd = selfData.event;
+ pd.in_flags = PR_POLL_READ;
+ for (i = 0; i < numIterations; i++) {
+ if (dally != PR_INTERVAL_NO_WAIT) {
+ PR_Sleep(dally);
+ }
+ if (verbosity) {
+ PR_fprintf(debug_out, "main thread posting event\n");
+ }
+ if (PR_SetPollableEvent(selfData.next->event) == PR_FAILURE) {
+ PR_fprintf(PR_STDERR, "set event failed\n");
+ exit(1);
+ }
+ rv = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT);
+ if (rv == -1) {
+ PR_fprintf(PR_STDERR, "wait failed\n");
+ exit(1);
+ }
+ PR_ASSERT(rv != 0);
+ PR_ASSERT(pd.out_flags & PR_POLL_READ);
+ if (verbosity) {
+ PR_fprintf(debug_out, "main thread awakened\n");
+ }
+ if (PR_WaitForPollableEvent(selfData.event) == PR_FAILURE) {
+ PR_fprintf(PR_STDERR, "consume event failed\n");
+ exit(1);
+ }
+ }
+ timeEnd = PR_IntervalNow();
+
+ if (debug_mode) {
+ average = PR_IntervalToMicroseconds(timeEnd - timeStart)
+ / (numIterations * numThreads);
+ PR_fprintf(debug_out, "Average switch times %d usecs for %d threads\n",
+ average, numThreads);
+ }
+
+ for (i = 0; i < numThreads; i++) {
+ if (PR_JoinThread(thread[i]) == PR_FAILURE) {
+ PR_fprintf(PR_STDERR, "join thread failed\n");
+ exit(1);
+ }
+ PR_DestroyPollableEvent(data[i].event);
+ }
+ PR_DELETE(block);
+ PR_DestroyPollableEvent(selfData.event);
+
+ PR_fprintf(PR_STDOUT, "PASSED\n");
+ return 0;
+}
diff --git a/nsprpub/pr/tests/prfdbl.c b/nsprpub/pr/tests/prfdbl.c
new file mode 100644
index 0000000000..3bb0650b2e
--- /dev/null
+++ b/nsprpub/pr/tests/prfdbl.c
@@ -0,0 +1,29 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * This is a simple test of the PR_fprintf() function for doubles.
+ */
+
+#include "prprf.h"
+
+int main()
+{
+ double pi = 3.1415926;
+ double e = 2.71828;
+ double root2 = 1.414;
+ double zero = 0.0;
+ double nan = zero / zero;
+
+ PR_fprintf(PR_STDOUT, "pi is %f.\n", pi);
+ PR_fprintf(PR_STDOUT, "e is %f.\n", e);
+ PR_fprintf(PR_STDOUT, "The square root of 2 is %f.\n", root2);
+ PR_fprintf(PR_STDOUT, "NaN is %f.\n", nan);
+
+ PR_fprintf(PR_STDOUT, "pi is %301f.\n", pi);
+ PR_fprintf(PR_STDOUT, "e is %65416.123f.\n", e);
+ PR_fprintf(PR_STDOUT, "e is %0000000000000000000065416.123f.\n", e);
+ PR_fprintf(PR_STDOUT, "NaN is %1024.1f.\n", nan);
+ return 0;
+}
diff --git a/nsprpub/pr/tests/prftest.c b/nsprpub/pr/tests/prftest.c
new file mode 100644
index 0000000000..091c990a79
--- /dev/null
+++ b/nsprpub/pr/tests/prftest.c
@@ -0,0 +1,66 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * File: prftest.c
+ * Description:
+ * This is a simple test of the PR_snprintf() function defined
+ * in prprf.c.
+ */
+
+#include "prlong.h"
+#include "prprf.h"
+
+#include <string.h>
+
+#define BUF_SIZE 128
+
+int main(int argc, char **argv)
+{
+ PRInt16 i16;
+ PRIntn n;
+ PRInt32 i32;
+ PRInt64 i64;
+ char buf[BUF_SIZE];
+ char answer[BUF_SIZE];
+ int i, rv = 0;
+
+ i16 = -1;
+ n = -1;
+ i32 = -1;
+ LL_I2L(i64, i32);
+
+ PR_snprintf(buf, BUF_SIZE, "%hx %x %lx %llx", i16, n, i32, i64);
+ strcpy(answer, "ffff ");
+ for (i = PR_BYTES_PER_INT * 2; i; i--) {
+ strcat(answer, "f");
+ }
+ strcat(answer, " ffffffff ffffffffffffffff");
+
+ if (!strcmp(buf, answer)) {
+ printf("PR_snprintf test 1 passed\n");
+ } else {
+ printf("PR_snprintf test 1 failed\n");
+ printf("Converted string is %s\n", buf);
+ printf("Should be %s\n", answer);
+ rv = 1;
+ }
+
+ i16 = -32;
+ n = 30;
+ i32 = 64;
+ LL_I2L(i64, 333);
+ PR_snprintf(buf, BUF_SIZE, "%d %hd %lld %ld", n, i16, i64, i32);
+ if (!strcmp(buf, "30 -32 333 64")) {
+ printf("PR_snprintf test 2 passed\n");
+ } else {
+ printf("PR_snprintf test 2 failed\n");
+ printf("Converted string is %s\n", buf);
+ printf("Should be 30 -32 333 64\n");
+ rv = 1;
+ }
+
+ return rv;
+}
diff --git a/nsprpub/pr/tests/prftest1.c b/nsprpub/pr/tests/prftest1.c
new file mode 100644
index 0000000000..5d6374a455
--- /dev/null
+++ b/nsprpub/pr/tests/prftest1.c
@@ -0,0 +1,129 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+** File: prftest1.c
+** Description:
+** This is a simple test of the PR_snprintf() function defined
+** in prprf.c.
+**
+** Modification History:
+** 14-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
+** The debug mode will print all of the printfs associated with this test.
+** The regress mode will be the default mode. Since the regress tool limits
+** the output to a one line status:PASS or FAIL,all of the printf statements
+** have been handled with an if (debug_mode) statement.
+***********************************************************************/
+/***********************************************************************
+** Includes
+***********************************************************************/
+/* Used to get the command line option */
+#include "plgetopt.h"
+#include "prttools.h"
+
+#include "prinit.h"
+#include "prlong.h"
+#include "prprf.h"
+
+#include <string.h>
+
+#define BUF_SIZE 128
+
+/***********************************************************************
+** PRIVATE FUNCTION: Test_Result
+** DESCRIPTION: Used in conjunction with the regress tool, prints out the
+** status of the test case.
+** INPUTS: PASS/FAIL
+** OUTPUTS: None
+** RETURN: None
+** SIDE EFFECTS:
+**
+** RESTRICTIONS:
+** None
+** MEMORY: NA
+** ALGORITHM: Determine what the status is and print accordingly.
+**
+***********************************************************************/
+
+
+static void Test_Result (int result)
+{
+ if (result == PASS) {
+ printf ("PASS\n");
+ }
+ else {
+ printf ("FAIL\n");
+ }
+}
+
+int main(int argc, char **argv)
+{
+ PRInt16 i16;
+ PRIntn n;
+ PRInt32 i32;
+ PRInt64 i64;
+ char buf[BUF_SIZE];
+ char answer[BUF_SIZE];
+ int i;
+
+ /* The command line argument: -d is used to determine if the test is being run
+ in debug mode. The regress tool requires only one line output:PASS or FAIL.
+ All of the printfs associated with this test has been handled with a if (debug_mode)
+ test.
+ Usage: test_name -d
+ */
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "d:");
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 'd': /* debug mode */
+ debug_mode = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ /* main test */
+ PR_STDIO_INIT();
+
+ i16 = -1;
+ n = -1;
+ i32 = -1;
+ LL_I2L(i64, i32);
+
+ PR_snprintf(buf, BUF_SIZE, "%hx %x %lx %llx", i16, n, i32, i64);
+ strcpy(answer, "ffff ");
+ for (i = PR_BYTES_PER_INT * 2; i; i--) {
+ strcat(answer, "f");
+ }
+ strcat(answer, " ffffffff ffffffffffffffff");
+
+ if (!strcmp(buf, answer)) {
+ if (debug_mode) {
+ printf("PR_snprintf test 1 passed\n");
+ }
+ else {
+ Test_Result (PASS);
+ }
+ } else {
+ if (debug_mode) {
+ printf("PR_snprintf test 1 failed\n");
+ printf("Converted string is %s\n", buf);
+ printf("Should be %s\n", answer);
+ }
+ else {
+ Test_Result (FAIL);
+ }
+ }
+
+ return 0;
+}
diff --git a/nsprpub/pr/tests/prftest2.c b/nsprpub/pr/tests/prftest2.c
new file mode 100644
index 0000000000..6376fd2ffd
--- /dev/null
+++ b/nsprpub/pr/tests/prftest2.c
@@ -0,0 +1,103 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+** File: prftest2.c
+** Description:
+** This is a simple test of the PR_snprintf() function defined
+** in prprf.c.
+**
+** Modification History:
+** 14-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
+** The debug mode will print all of the printfs associated with this test.
+** The regress mode will be the default mode. Since the regress tool limits
+** the output to a one line status:PASS or FAIL,all of the printf statements
+** have been handled with an if (debug_mode) statement.
+** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to
+** recognize the return code from tha main program.
+***********************************************************************/
+/***********************************************************************
+** Includes
+***********************************************************************/
+/* Used to get the command line option */
+#include "plgetopt.h"
+
+#include "prlong.h"
+#include "prinit.h"
+#include "prprf.h"
+
+#include <string.h>
+
+#define BUF_SIZE 128
+
+PRIntn failed_already=0;
+PRIntn debug_mode;
+
+int main(int argc, char **argv)
+{
+ PRInt16 i16;
+ PRIntn n;
+ PRInt32 i32;
+ PRInt64 i64;
+ char buf[BUF_SIZE];
+
+ /* The command line argument: -d is used to determine if the test is being run
+ in debug mode. The regress tool requires only one line output:PASS or FAIL.
+ All of the printfs associated with this test has been handled with a if (debug_mode)
+ test.
+ Usage: test_name -d
+ */
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "d:");
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 'd': /* debug mode */
+ debug_mode = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ /* main test */
+
+
+ PR_STDIO_INIT();
+ i16 = -32;
+ n = 30;
+ i32 = 64;
+ LL_I2L(i64, 333);
+ PR_snprintf(buf, BUF_SIZE, "%d %hd %lld %ld", n, i16, i64, i32);
+ if (!strcmp(buf, "30 -32 333 64")) {
+ if (debug_mode) {
+ printf("PR_snprintf test 2 passed\n");
+ }
+ } else {
+ if (debug_mode) {
+ printf("PR_snprintf test 2 failed\n");
+ printf("Converted string is %s\n", buf);
+ printf("Should be 30 -32 333 64\n");
+ }
+ else {
+ failed_already=1;
+ }
+ }
+ if(failed_already)
+ {
+ printf("FAILED\n");
+ return 1;
+ }
+ else
+ {
+ printf("PASSED\n");
+ return 0;
+ }
+}
diff --git a/nsprpub/pr/tests/prfz.c b/nsprpub/pr/tests/prfz.c
new file mode 100644
index 0000000000..7179dbecdb
--- /dev/null
+++ b/nsprpub/pr/tests/prfz.c
@@ -0,0 +1,85 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * This is a simple test of the PR_fprintf() function for size_t formats.
+ */
+
+#include "prprf.h"
+#include <sys/types.h>
+#include <limits.h>
+#include <string.h>
+#include <stdint.h>
+
+int
+main(int argc, char **argv)
+{
+ char buffer[128];
+
+ size_t unsigned_small = 266;
+#ifdef XP_UNIX
+ ssize_t signed_small_p = 943;
+ ssize_t signed_small_n = -1;
+#endif
+ size_t unsigned_max = SIZE_MAX;
+ size_t unsigned_min = 0;
+#ifdef XP_UNIX
+ ssize_t signed_max = SSIZE_MAX;
+#endif
+
+ printf("Test: unsigned small '%%zu' : ");
+ PR_snprintf(buffer, sizeof(buffer), "%zu", unsigned_small);
+ if (strncmp(buffer, "266", sizeof(buffer)) != 0) {
+ printf("Failed, got '%s'\n", buffer);
+ return -1;
+ }
+ printf("OK\n");
+
+#ifdef XP_UNIX
+ printf("Test: signed small positive '%%zd' : ");
+ PR_snprintf(buffer, sizeof(buffer), "%zd", signed_small_p);
+ if (strncmp(buffer, "943", sizeof(buffer)) != 0) {
+ printf("Failed, got '%s'\n", buffer);
+ return -1;
+ }
+ printf("OK\n");
+
+ printf("Test: signed small negative '%%zd' : ");
+ PR_snprintf(buffer, sizeof(buffer), "%zd", signed_small_n);
+ if (strncmp(buffer, "-1", sizeof(buffer)) != 0) {
+ printf("Failed, got '%s'\n", buffer);
+ return -1;
+ }
+ printf("OK\n");
+#endif
+
+ printf("Test: 0 '%%zu' : ");
+ PR_snprintf(buffer, sizeof(buffer), "%zu", unsigned_min);
+ if (strncmp(buffer, "0", sizeof(buffer)) != 0) {
+ printf("Failed, got '%s'\n", buffer);
+ return -1;
+ }
+ printf("OK\n");
+
+ printf("Test: SIZE_MAX '%%zx' : ");
+ PR_snprintf(buffer, sizeof(buffer), "%zx", unsigned_max);
+ if (strspn(buffer, "f") != sizeof(size_t) * 2) {
+ printf("Failed, got '%s'\n", buffer);
+ return -1;
+ }
+ printf("OK\n");
+
+#ifdef XP_UNIX
+ printf("Test: SSIZE_MAX '%%zx' : ");
+ PR_snprintf(buffer, sizeof(buffer), "%zx", signed_max);
+ if (*buffer != '7' ||
+ strspn(buffer + 1, "f") != sizeof(ssize_t) * 2 - 1) {
+ printf("Failed, got '%s'\n", buffer);
+ return -1;
+ }
+ printf("OK\n");
+#endif
+
+ return 0;
+}
diff --git a/nsprpub/pr/tests/primblok.c b/nsprpub/pr/tests/primblok.c
new file mode 100644
index 0000000000..1182d3ed73
--- /dev/null
+++ b/nsprpub/pr/tests/primblok.c
@@ -0,0 +1,116 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * File: primblok.c
+ * Purpose: testing whether the primordial thread can block in a
+ * native blocking function without affecting the correct
+ * functioning of NSPR I/O functions (Bugzilla bug #30746)
+ */
+
+#if !defined(WINNT)
+
+#include <stdio.h>
+
+int main(int argc, char **argv)
+{
+ printf("This test is not relevant on this platform\n");
+ return 0;
+}
+
+#else /* WINNT */
+
+#include "nspr.h"
+
+#include <windows.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define TEST_FILE_NAME "primblok.dat"
+
+/* use InterlockedExchange to update this variable */
+static LONG iothread_done;
+
+static void PR_CALLBACK IOThread(void *arg)
+{
+ PRFileDesc *fd;
+ char buf[32];
+ PRInt32 nbytes;
+
+ /* Give the primordial thread one second to block */
+ Sleep(1000);
+
+ /*
+ * See if our PR_Write call will hang when the primordial
+ * thread is blocking in a native blocking function.
+ */
+ fd = PR_Open(TEST_FILE_NAME, PR_WRONLY|PR_CREATE_FILE, 0666);
+ if (NULL == fd) {
+ fprintf(stderr, "PR_Open failed\n");
+ exit(1);
+ }
+ memset(buf, 0xaf, sizeof(buf));
+ fprintf(stderr, "iothread: calling PR_Write\n");
+ nbytes = PR_Write(fd, buf, sizeof(buf));
+ fprintf(stderr, "iothread: PR_Write returned\n");
+ if (nbytes != sizeof(buf)) {
+ fprintf(stderr, "PR_Write returned %d\n", nbytes);
+ exit(1);
+ }
+ if (PR_Close(fd) == PR_FAILURE) {
+ fprintf(stderr, "PR_Close failed\n");
+ exit(1);
+ }
+ if (PR_Delete(TEST_FILE_NAME) == PR_FAILURE) {
+ fprintf(stderr, "PR_Delete failed\n");
+ exit(1);
+ }
+
+ /* Tell the main thread that we are done */
+ InterlockedExchange(&iothread_done, 1);
+}
+
+int main(int argc, char **argv)
+{
+ PRThread *iothread;
+
+ /* Must be a global thread */
+ iothread = PR_CreateThread(
+ PR_USER_THREAD, IOThread, NULL, PR_PRIORITY_NORMAL,
+ PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0);
+ if (iothread == NULL) {
+ fprintf(stderr, "cannot create thread\n");
+ exit(1);
+ }
+
+ /*
+ * Block in a native blocking function.
+ * Give iothread 5 seconds to finish its task.
+ */
+ Sleep(5000);
+
+ /*
+ * Is iothread done or is it hung?
+ *
+ * I'm actually only interested in reading the value
+ * of iothread_done. I'm using InterlockedExchange as
+ * a thread-safe way to read iothread_done.
+ */
+ if (InterlockedExchange(&iothread_done, 1) == 0) {
+ fprintf(stderr, "iothread is hung\n");
+ fprintf(stderr, "FAILED\n");
+ exit(1);
+ }
+
+ if (PR_JoinThread(iothread) == PR_FAILURE) {
+ fprintf(stderr, "PR_JoinThread failed\n");
+ exit(1);
+ }
+ printf("PASSED\n");
+ return 0;
+} /* main */
+
+#endif /* WINNT */
diff --git a/nsprpub/pr/tests/priotest.c b/nsprpub/pr/tests/priotest.c
new file mode 100644
index 0000000000..1e2249de63
--- /dev/null
+++ b/nsprpub/pr/tests/priotest.c
@@ -0,0 +1,202 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * File: priotest.c
+ * Purpose: testing priorities
+ */
+
+#include "prcmon.h"
+#include "prinit.h"
+#include "prinrval.h"
+#include "prlock.h"
+#include "prlog.h"
+#include "prmon.h"
+#include "prprf.h"
+#include "prthread.h"
+#include "prtypes.h"
+
+#include "plerror.h"
+#include "plgetopt.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#define DEFAULT_DURATION 5
+
+static PRBool failed = PR_FALSE;
+static PRIntervalTime oneSecond;
+static PRFileDesc *debug_out = NULL;
+static PRBool debug_mode = PR_FALSE;
+
+static PRUint32 PerSecond(PRIntervalTime timein)
+{
+ PRUint32 loop = 0;
+ while (((PRIntervalTime)(PR_IntervalNow()) - timein) < oneSecond) {
+ loop += 1;
+ }
+ return loop;
+} /* PerSecond */
+
+static void PR_CALLBACK Low(void *arg)
+{
+ PRUint32 t3 = 0, t2 = 0, t1 = 0, t0, *tn = (PRUint32*)arg;
+ while (1)
+ {
+ t0 = PerSecond(PR_IntervalNow());
+ *tn = (t3 + 3 * t2 + 3 * t1 + t0) / 8;
+ t3 = t2; t2 = t1; t1 = t0;
+ }
+} /* Low */
+
+static void PR_CALLBACK High(void *arg)
+{
+ PRUint32 t3 = 0, t2 = 0, t1 = 0, t0, *tn = (PRUint32*)arg;
+ while (1)
+ {
+ PRIntervalTime timein = PR_IntervalNow();
+ PR_Sleep(oneSecond >> 2); /* 0.25 seconds */
+ t0 = PerSecond(timein);
+ *tn = (t3 + 3 * t2 + 3 * t1 + t0) / 8;
+ t3 = t2; t2 = t1; t1 = t0;
+ }
+} /* High */
+
+static void Help(void)
+{
+ PR_fprintf(
+ debug_out, "Usage: priotest [-d] [-c n]\n");
+ PR_fprintf(
+ debug_out, "-c n\tduration of test in seconds (default: %d)\n", DEFAULT_DURATION);
+ PR_fprintf(
+ debug_out, "-d\tturn on debugging output (default: FALSE)\n");
+} /* Help */
+
+static void RudimentaryTests(void)
+{
+ /*
+ ** Try some rudimentary tests like setting valid priority and
+ ** getting it back, or setting invalid priorities and getting
+ ** back a valid answer.
+ */
+ PRThreadPriority priority;
+ PR_SetThreadPriority(PR_GetCurrentThread(), PR_PRIORITY_URGENT);
+ priority = PR_GetThreadPriority(PR_GetCurrentThread());
+ failed = ((PR_TRUE == failed) || (PR_PRIORITY_URGENT != priority))
+ ? PR_TRUE : PR_FALSE;
+ if (debug_mode && (PR_PRIORITY_URGENT != priority))
+ {
+ PR_fprintf(debug_out, "PR_[S/G]etThreadPriority() failed\n");
+ }
+
+
+ PR_SetThreadPriority(
+ PR_GetCurrentThread(), (PRThreadPriority)(PR_PRIORITY_FIRST - 1));
+ priority = PR_GetThreadPriority(PR_GetCurrentThread());
+ failed = ((PR_TRUE == failed) || (PR_PRIORITY_FIRST != priority))
+ ? PR_TRUE : PR_FALSE;
+ if (debug_mode && (PR_PRIORITY_FIRST != priority))
+ {
+ PR_fprintf(debug_out, "PR_SetThreadPriority(-1) failed\n");
+ }
+
+ PR_SetThreadPriority(
+ PR_GetCurrentThread(), (PRThreadPriority)(PR_PRIORITY_LAST + 1));
+ priority = PR_GetThreadPriority(PR_GetCurrentThread());
+ failed = ((PR_TRUE == failed) || (PR_PRIORITY_LAST != priority))
+ ? PR_TRUE : PR_FALSE;
+ if (debug_mode && (PR_PRIORITY_LAST != priority))
+ {
+ PR_fprintf(debug_out, "PR_SetThreadPriority(+1) failed\n");
+ }
+
+} /* RudimentataryTests */
+
+static void CreateThreads(PRUint32 *lowCount, PRUint32 *highCount)
+{
+ (void)PR_CreateThread(
+ PR_USER_THREAD, Low, lowCount, PR_PRIORITY_LOW,
+ PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0);
+ (void)PR_CreateThread(
+ PR_USER_THREAD, High, highCount, PR_PRIORITY_HIGH,
+ PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0);
+} /* CreateThreads */
+
+int main(int argc, char **argv)
+{
+ PLOptStatus os;
+ PRIntn duration = DEFAULT_DURATION;
+ PRUint32 totalCount, highCount = 0, lowCount = 0;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "hdc:");
+
+ debug_out = PR_STDOUT;
+ oneSecond = PR_SecondsToInterval(1);
+
+ 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': /* test duration */
+ duration = atoi(opt->value);
+ break;
+ case 'h': /* help message */
+ default:
+ Help();
+ return 2;
+ }
+ }
+ PL_DestroyOptState(opt);
+ PR_STDIO_INIT();
+
+ if (duration == 0) {
+ duration = DEFAULT_DURATION;
+ }
+
+ RudimentaryTests();
+
+ printf("Priority test: running for %d seconds\n\n", duration);
+
+ (void)PerSecond(PR_IntervalNow());
+ totalCount = PerSecond(PR_IntervalNow());
+
+ PR_SetThreadPriority(PR_GetCurrentThread(), PR_PRIORITY_URGENT);
+
+ if (debug_mode)
+ {
+ PR_fprintf(debug_out,
+ "The high priority thread should get approximately three\n");
+ PR_fprintf( debug_out,
+ "times what the low priority thread manages. A maximum of \n");
+ PR_fprintf( debug_out, "%d cycles are available.\n\n", totalCount);
+ }
+
+ duration = (duration + 4) / 5;
+ CreateThreads(&lowCount, &highCount);
+ while (duration--)
+ {
+ PRIntn loop = 5;
+ while (loop--) {
+ PR_Sleep(oneSecond);
+ }
+ if (debug_mode) {
+ PR_fprintf(debug_out, "high : low :: %d : %d\n", highCount, lowCount);
+ }
+ }
+
+
+ PR_ProcessExit((failed) ? 1 : 0);
+
+ PR_NOT_REACHED("You can't get here -- but you did!");
+ return 1; /* or here */
+
+} /* main */
+
+/* priotest.c */
diff --git a/nsprpub/pr/tests/provider.c b/nsprpub/pr/tests/provider.c
new file mode 100644
index 0000000000..3450b20aea
--- /dev/null
+++ b/nsprpub/pr/tests/provider.c
@@ -0,0 +1,1412 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ *
+ * Notes:
+ * [1] lth. The call to Sleep() is a hack to get the test case to run
+ * on Windows 95. Without it, the test case fails with an error
+ * WSAECONNRESET following a recv() call. The error is caused by the
+ * server side thread termination without a shutdown() or closesocket()
+ * call. Windows docmunentation suggests that this is predicted
+ * behavior; that other platforms get away with it is ... serindipity.
+ * The test case should shutdown() or closesocket() before
+ * thread termination. I didn't have time to figure out where or how
+ * to do it. The Sleep() call inserts enough delay to allow the
+ * client side to recv() all his data before the server side thread
+ * terminates. Whew! ...
+ *
+ ** Modification History:
+ * 14-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
+ * The debug mode will print all of the printfs associated with this test.
+ * The regress mode will be the default mode. Since the regress tool limits
+ * the output to a one line status:PASS or FAIL,all of the printf statements
+ * have been handled with an if (debug_mode) statement.
+ */
+
+#include "prclist.h"
+#include "prcvar.h"
+#include "prerror.h"
+#include "prinit.h"
+#include "prinrval.h"
+#include "prio.h"
+#include "prlock.h"
+#include "prlog.h"
+#include "prtime.h"
+#include "prmem.h"
+#include "prnetdb.h"
+#include "prprf.h"
+#include "prthread.h"
+
+#include "pprio.h"
+#include "primpl.h"
+
+#include "plstr.h"
+#include "plerror.h"
+#include "plgetopt.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#if defined(XP_UNIX)
+#include <math.h>
+#endif
+
+/*
+** This is the beginning of the test
+*/
+
+#ifdef DEBUG
+#define PORT_INC_DO +100
+#else
+#define PORT_INC_DO
+#endif
+#ifdef IS_64
+#define PORT_INC_3264 +200
+#else
+#define PORT_INC_3264
+#endif
+
+#define RECV_FLAGS 0
+#define SEND_FLAGS 0
+#define BUFFER_SIZE 1024
+#define DEFAULT_BACKLOG 5
+#define DEFAULT_PORT 13000 PORT_INC_DO PORT_INC_3264
+#define DEFAULT_CLIENTS 1
+#define ALLOWED_IN_ACCEPT 1
+#define DEFAULT_CLIPPING 1000
+#define DEFAULT_WORKERS_MIN 1
+#define DEFAULT_WORKERS_MAX 1
+#define DEFAULT_SERVER "localhost"
+#define DEFAULT_EXECUTION_TIME 10
+#define DEFAULT_CLIENT_TIMEOUT 4000
+#define DEFAULT_SERVER_TIMEOUT 4000
+#define DEFAULT_SERVER_PRIORITY PR_PRIORITY_HIGH
+
+typedef enum CSState_e {cs_init, cs_run, cs_stop, cs_exit} CSState_t;
+
+static void PR_CALLBACK Worker(void *arg);
+typedef struct CSPool_s CSPool_t;
+typedef struct CSWorker_s CSWorker_t;
+typedef struct CSServer_s CSServer_t;
+typedef enum Verbosity
+{
+ TEST_LOG_ALWAYS,
+ TEST_LOG_ERROR,
+ TEST_LOG_WARNING,
+ TEST_LOG_NOTICE,
+ TEST_LOG_INFO,
+ TEST_LOG_STATUS,
+ TEST_LOG_VERBOSE
+} Verbosity;
+
+static enum {
+ thread_nspr, thread_pthread, thread_sproc, thread_win32
+} thread_provider;
+
+static PRInt32 domain = AF_INET;
+static PRInt32 protocol = 6; /* TCP */
+static PRFileDesc *debug_out = NULL;
+static PRBool debug_mode = PR_FALSE;
+static PRBool pthread_stats = PR_FALSE;
+static Verbosity verbosity = TEST_LOG_ALWAYS;
+static PRThreadScope thread_scope = PR_LOCAL_THREAD;
+
+struct CSWorker_s
+{
+ PRCList element; /* list of the server's workers */
+
+ PRThread *thread; /* this worker objects thread */
+ CSServer_t *server; /* back pointer to server structure */
+};
+
+struct CSPool_s
+{
+ PRCondVar *exiting;
+ PRCondVar *acceptComplete;
+ PRUint32 accepting, active, workers;
+};
+
+struct CSServer_s
+{
+ PRCList list; /* head of worker list */
+
+ PRLock *ml;
+ PRThread *thread; /* the main server thread */
+ PRCondVar *stateChange;
+
+ PRUint16 port; /* port we're listening on */
+ PRUint32 backlog; /* size of our listener backlog */
+ PRFileDesc *listener; /* the fd accepting connections */
+
+ CSPool_t pool; /* statistics on worker threads */
+ CSState_t state; /* the server's state */
+ struct /* controlling worker counts */
+ {
+ PRUint32 minimum, maximum, accepting;
+ } workers;
+
+ /* statistics */
+ PRIntervalTime started, stopped;
+ PRUint32 operations, bytesTransferred;
+};
+
+typedef struct CSDescriptor_s
+{
+ PRInt32 size; /* size of transfer */
+ char filename[60]; /* filename, null padded */
+} CSDescriptor_t;
+
+typedef struct CSClient_s
+{
+ PRLock *ml;
+ PRThread *thread;
+ PRCondVar *stateChange;
+ PRNetAddr serverAddress;
+
+ CSState_t state;
+
+ /* statistics */
+ PRIntervalTime started, stopped;
+ PRUint32 operations, bytesTransferred;
+} CSClient_t;
+
+#define TEST_LOG(l, p, a) \
+ do { \
+ if (debug_mode || (p <= verbosity)) printf a; \
+ } while (0)
+
+PRLogModuleInfo *cltsrv_log_file = NULL;
+
+#define MY_ASSERT(_expr) \
+ ((_expr)?((void)0):_MY_Assert(# _expr,__FILE__,__LINE__))
+
+#define TEST_ASSERT(_expr) \
+ ((_expr)?((void)0):_MY_Assert(# _expr,__FILE__,__LINE__))
+
+static void _MY_Assert(const char *s, const char *file, PRIntn ln)
+{
+ PL_PrintError(NULL);
+ PR_Assert(s, file, ln);
+} /* _MY_Assert */
+
+static PRBool Aborted(PRStatus rv)
+{
+ return ((PR_FAILURE == rv) && (PR_PENDING_INTERRUPT_ERROR == PR_GetError())) ?
+ PR_TRUE : PR_FALSE;
+}
+
+static void TimeOfDayMessage(const char *msg, PRThread* me)
+{
+ char buffer[100];
+ PRExplodedTime tod;
+ PR_ExplodeTime(PR_Now(), PR_LocalTimeParameters, &tod);
+ (void)PR_FormatTime(buffer, sizeof(buffer), "%H:%M:%S", &tod);
+
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_ALWAYS,
+ ("%s(0x%p): %s\n", msg, me, buffer));
+} /* TimeOfDayMessage */
+
+
+static void PR_CALLBACK Client(void *arg)
+{
+ PRStatus rv;
+ PRIntn index;
+ char buffer[1024];
+ PRFileDesc *fd = NULL;
+ PRUintn clipping = DEFAULT_CLIPPING;
+ CSClient_t *client = (CSClient_t*)arg;
+ PRThread *me = client->thread = PR_GetCurrentThread();
+ CSDescriptor_t *descriptor = PR_NEW(CSDescriptor_t);
+ PRIntervalTime timeout = PR_MillisecondsToInterval(DEFAULT_CLIENT_TIMEOUT);
+
+
+ for (index = 0; index < sizeof(buffer); ++index) {
+ buffer[index] = (char)index;
+ }
+
+ client->started = PR_IntervalNow();
+
+ PR_Lock(client->ml);
+ client->state = cs_run;
+ PR_NotifyCondVar(client->stateChange);
+ PR_Unlock(client->ml);
+
+ TimeOfDayMessage("Client started at", me);
+
+ while (cs_run == client->state)
+ {
+ PRInt32 bytes, descbytes, filebytes, netbytes;
+
+ (void)PR_NetAddrToString(&client->serverAddress, buffer, sizeof(buffer));
+ TEST_LOG(cltsrv_log_file, TEST_LOG_INFO,
+ ("\tClient(0x%p): connecting to server at %s\n", me, buffer));
+
+ fd = PR_Socket(domain, SOCK_STREAM, protocol);
+ TEST_ASSERT(NULL != fd);
+ rv = PR_Connect(fd, &client->serverAddress, timeout);
+ if (PR_FAILURE == rv)
+ {
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_ERROR,
+ ("\tClient(0x%p): conection failed\n", me));
+ goto aborted;
+ }
+
+ memset(descriptor, 0, sizeof(*descriptor));
+ descriptor->size = PR_htonl(descbytes = rand() % clipping);
+ PR_snprintf(
+ descriptor->filename, sizeof(descriptor->filename),
+ "CS%p%p-%p.dat", client->started, me, client->operations);
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_VERBOSE,
+ ("\tClient(0x%p): sending descriptor for %u bytes\n", me, descbytes));
+ bytes = PR_Send(
+ fd, descriptor, sizeof(*descriptor), SEND_FLAGS, timeout);
+ if (sizeof(CSDescriptor_t) != bytes)
+ {
+ if (Aborted(PR_FAILURE)) {
+ goto aborted;
+ }
+ if (PR_IO_TIMEOUT_ERROR == PR_GetError())
+ {
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_ERROR,
+ ("\tClient(0x%p): send descriptor timeout\n", me));
+ goto retry;
+ }
+ }
+ TEST_ASSERT(sizeof(*descriptor) == bytes);
+
+ netbytes = 0;
+ while (netbytes < descbytes)
+ {
+ filebytes = sizeof(buffer);
+ if ((descbytes - netbytes) < filebytes) {
+ filebytes = descbytes - netbytes;
+ }
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_VERBOSE,
+ ("\tClient(0x%p): sending %d bytes\n", me, filebytes));
+ bytes = PR_Send(fd, buffer, filebytes, SEND_FLAGS, timeout);
+ if (filebytes != bytes)
+ {
+ if (Aborted(PR_FAILURE)) {
+ goto aborted;
+ }
+ if (PR_IO_TIMEOUT_ERROR == PR_GetError())
+ {
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_ERROR,
+ ("\tClient(0x%p): send data timeout\n", me));
+ goto retry;
+ }
+ }
+ TEST_ASSERT(bytes == filebytes);
+ netbytes += bytes;
+ }
+ filebytes = 0;
+ while (filebytes < descbytes)
+ {
+ netbytes = sizeof(buffer);
+ if ((descbytes - filebytes) < netbytes) {
+ netbytes = descbytes - filebytes;
+ }
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_VERBOSE,
+ ("\tClient(0x%p): receiving %d bytes\n", me, netbytes));
+ bytes = PR_Recv(fd, buffer, netbytes, RECV_FLAGS, timeout);
+ if (-1 == bytes)
+ {
+ if (Aborted(PR_FAILURE))
+ {
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_ERROR,
+ ("\tClient(0x%p): receive data aborted\n", me));
+ goto aborted;
+ }
+ else if (PR_IO_TIMEOUT_ERROR == PR_GetError())
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_ERROR,
+ ("\tClient(0x%p): receive data timeout\n", me));
+ else
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_ERROR,
+ ("\tClient(0x%p): receive error (%d, %d)\n",
+ me, PR_GetError(), PR_GetOSError()));
+ goto retry;
+ }
+ if (0 == bytes)
+ {
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_ERROR,
+ ("\t\tClient(0x%p): unexpected end of stream\n",
+ PR_GetCurrentThread()));
+ break;
+ }
+ filebytes += bytes;
+ }
+
+ rv = PR_Shutdown(fd, PR_SHUTDOWN_BOTH);
+ if (Aborted(rv)) {
+ goto aborted;
+ }
+ TEST_ASSERT(PR_SUCCESS == rv);
+retry:
+ (void)PR_Close(fd); fd = NULL;
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_INFO,
+ ("\tClient(0x%p): disconnected from server\n", me));
+
+ PR_Lock(client->ml);
+ client->operations += 1;
+ client->bytesTransferred += 2 * descbytes;
+ rv = PR_WaitCondVar(client->stateChange, rand() % clipping);
+ PR_Unlock(client->ml);
+ if (Aborted(rv)) {
+ break;
+ }
+ }
+
+aborted:
+ client->stopped = PR_IntervalNow();
+
+ PR_ClearInterrupt();
+ if (NULL != fd) {
+ rv = PR_Close(fd);
+ }
+
+ PR_Lock(client->ml);
+ client->state = cs_exit;
+ PR_NotifyCondVar(client->stateChange);
+ PR_Unlock(client->ml);
+ PR_DELETE(descriptor);
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_ALWAYS,
+ ("\tClient(0x%p): stopped after %u operations and %u bytes\n",
+ PR_GetCurrentThread(), client->operations, client->bytesTransferred));
+
+} /* Client */
+
+static PRStatus ProcessRequest(PRFileDesc *fd, CSServer_t *server)
+{
+ PRStatus drv, rv;
+ char buffer[1024];
+ PRFileDesc *file = NULL;
+ PRThread * me = PR_GetCurrentThread();
+ PRInt32 bytes, descbytes, netbytes, filebytes = 0;
+ CSDescriptor_t *descriptor = PR_NEW(CSDescriptor_t);
+ PRIntervalTime timeout = PR_MillisecondsToInterval(DEFAULT_SERVER_TIMEOUT);
+
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_VERBOSE,
+ ("\tProcessRequest(0x%p): receiving desciptor\n", me));
+ bytes = PR_Recv(
+ fd, descriptor, sizeof(*descriptor), RECV_FLAGS, timeout);
+ if (-1 == bytes)
+ {
+ rv = PR_FAILURE;
+ if (Aborted(rv)) {
+ goto exit;
+ }
+ if (PR_IO_TIMEOUT_ERROR == PR_GetError())
+ {
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_ERROR,
+ ("\tProcessRequest(0x%p): receive timeout\n", me));
+ }
+ goto exit;
+ }
+ if (0 == bytes)
+ {
+ rv = PR_FAILURE;
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_ERROR,
+ ("\tProcessRequest(0x%p): unexpected end of file\n", me));
+ goto exit;
+ }
+ descbytes = PR_ntohl(descriptor->size);
+ TEST_ASSERT(sizeof(*descriptor) == bytes);
+
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_VERBOSE,
+ ("\t\tProcessRequest(0x%p): read descriptor {%d, %s}\n",
+ me, descbytes, descriptor->filename));
+
+ file = PR_Open(
+ descriptor->filename, (PR_CREATE_FILE | PR_WRONLY), 0666);
+ if (NULL == file)
+ {
+ rv = PR_FAILURE;
+ if (Aborted(rv)) {
+ goto aborted;
+ }
+ if (PR_IO_TIMEOUT_ERROR == PR_GetError())
+ {
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_ERROR,
+ ("\tProcessRequest(0x%p): open file timeout\n", me));
+ goto aborted;
+ }
+ }
+ TEST_ASSERT(NULL != file);
+
+ filebytes = 0;
+ while (filebytes < descbytes)
+ {
+ netbytes = sizeof(buffer);
+ if ((descbytes - filebytes) < netbytes) {
+ netbytes = descbytes - filebytes;
+ }
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_VERBOSE,
+ ("\tProcessRequest(0x%p): receive %d bytes\n", me, netbytes));
+ bytes = PR_Recv(fd, buffer, netbytes, RECV_FLAGS, timeout);
+ if (-1 == bytes)
+ {
+ rv = PR_FAILURE;
+ if (Aborted(rv)) {
+ goto aborted;
+ }
+ if (PR_IO_TIMEOUT_ERROR == PR_GetError())
+ {
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_ERROR,
+ ("\t\tProcessRequest(0x%p): receive data timeout\n", me));
+ goto aborted;
+ }
+ /*
+ * XXX: I got (PR_CONNECT_RESET_ERROR, ERROR_NETNAME_DELETED)
+ * on NT here. This is equivalent to ECONNRESET on Unix.
+ * -wtc
+ */
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_WARNING,
+ ("\t\tProcessRequest(0x%p): unexpected error (%d, %d)\n",
+ me, PR_GetError(), PR_GetOSError()));
+ goto aborted;
+ }
+ if(0 == bytes)
+ {
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_WARNING,
+ ("\t\tProcessRequest(0x%p): unexpected end of stream\n", me));
+ rv = PR_FAILURE;
+ goto aborted;
+ }
+ filebytes += bytes;
+ netbytes = bytes;
+ /* The byte count for PR_Write should be positive */
+ MY_ASSERT(netbytes > 0);
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_VERBOSE,
+ ("\tProcessRequest(0x%p): write %d bytes to file\n", me, netbytes));
+ bytes = PR_Write(file, buffer, netbytes);
+ if (netbytes != bytes)
+ {
+ rv = PR_FAILURE;
+ if (Aborted(rv)) {
+ goto aborted;
+ }
+ if (PR_IO_TIMEOUT_ERROR == PR_GetError())
+ {
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_ERROR,
+ ("\t\tProcessRequest(0x%p): write file timeout\n", me));
+ goto aborted;
+ }
+ }
+ TEST_ASSERT(bytes > 0);
+ }
+
+ PR_Lock(server->ml);
+ server->operations += 1;
+ server->bytesTransferred += filebytes;
+ PR_Unlock(server->ml);
+
+ rv = PR_Close(file); file = NULL;
+ if (Aborted(rv)) {
+ goto aborted;
+ }
+ TEST_ASSERT(PR_SUCCESS == rv);
+
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_VERBOSE,
+ ("\t\tProcessRequest(0x%p): opening %s\n", me, descriptor->filename));
+ file = PR_Open(descriptor->filename, PR_RDONLY, 0);
+ if (NULL == file)
+ {
+ rv = PR_FAILURE;
+ if (Aborted(rv)) {
+ goto aborted;
+ }
+ if (PR_IO_TIMEOUT_ERROR == PR_GetError())
+ {
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_ERROR,
+ ("\t\tProcessRequest(0x%p): open file timeout\n",
+ PR_GetCurrentThread()));
+ goto aborted;
+ }
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_ERROR,
+ ("\t\tProcessRequest(0x%p): other file open error (%u, %u)\n",
+ me, PR_GetError(), PR_GetOSError()));
+ goto aborted;
+ }
+ TEST_ASSERT(NULL != file);
+
+ netbytes = 0;
+ while (netbytes < descbytes)
+ {
+ filebytes = sizeof(buffer);
+ if ((descbytes - netbytes) < filebytes) {
+ filebytes = descbytes - netbytes;
+ }
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_VERBOSE,
+ ("\tProcessRequest(0x%p): read %d bytes from file\n", me, filebytes));
+ bytes = PR_Read(file, buffer, filebytes);
+ if (filebytes != bytes)
+ {
+ rv = PR_FAILURE;
+ if (Aborted(rv)) {
+ goto aborted;
+ }
+ if (PR_IO_TIMEOUT_ERROR == PR_GetError())
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_ERROR,
+ ("\t\tProcessRequest(0x%p): read file timeout\n", me));
+ else
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_ERROR,
+ ("\t\tProcessRequest(0x%p): other file error (%d, %d)\n",
+ me, PR_GetError(), PR_GetOSError()));
+ goto aborted;
+ }
+ TEST_ASSERT(bytes > 0);
+ netbytes += bytes;
+ filebytes = bytes;
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_VERBOSE,
+ ("\t\tProcessRequest(0x%p): sending %d bytes\n", me, filebytes));
+ bytes = PR_Send(fd, buffer, filebytes, SEND_FLAGS, timeout);
+ if (filebytes != bytes)
+ {
+ rv = PR_FAILURE;
+ if (Aborted(rv)) {
+ goto aborted;
+ }
+ if (PR_IO_TIMEOUT_ERROR == PR_GetError())
+ {
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_ERROR,
+ ("\t\tProcessRequest(0x%p): send data timeout\n", me));
+ goto aborted;
+ }
+ break;
+ }
+ TEST_ASSERT(bytes > 0);
+ }
+
+ PR_Lock(server->ml);
+ server->bytesTransferred += filebytes;
+ PR_Unlock(server->ml);
+
+ rv = PR_Shutdown(fd, PR_SHUTDOWN_BOTH);
+ if (Aborted(rv)) {
+ goto aborted;
+ }
+
+ rv = PR_Close(file); file = NULL;
+ if (Aborted(rv)) {
+ goto aborted;
+ }
+ TEST_ASSERT(PR_SUCCESS == rv);
+
+aborted:
+ PR_ClearInterrupt();
+ if (NULL != file) {
+ PR_Close(file);
+ }
+ drv = PR_Delete(descriptor->filename);
+ TEST_ASSERT(PR_SUCCESS == drv);
+exit:
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_VERBOSE,
+ ("\t\tProcessRequest(0x%p): Finished\n", me));
+
+ PR_DELETE(descriptor);
+
+#if defined(WIN95)
+ PR_Sleep(PR_MillisecondsToInterval(200)); /* lth. see note [1] */
+#endif
+ return rv;
+} /* ProcessRequest */
+
+typedef void (*StartFn)(void*);
+typedef struct StartObject
+{
+ StartFn start;
+ void *arg;
+} StartObject;
+
+#if defined(_PR_PTHREADS)
+#include "md/_pth.h"
+#include <pthread.h>
+
+static void *pthread_start(void *arg)
+{
+ StartObject *so = (StartObject*)arg;
+ StartFn start = so->start;
+ void *data = so->arg;
+ PR_Free(so);
+ start(data);
+ return NULL;
+} /* pthread_start */
+#endif /* defined(_PR_PTHREADS) */
+
+#if defined(WIN32)
+#include <process.h> /* for _beginthreadex() */
+
+static PRUintn __stdcall windows_start(void *arg)
+{
+ StartObject *so = (StartObject*)arg;
+ StartFn start = so->start;
+ void *data = so->arg;
+ PR_Free(so);
+ start(data);
+ return 0;
+} /* windows_start */
+#endif /* defined(WIN32) */
+
+static PRStatus JoinThread(PRThread *thread)
+{
+ PRStatus rv;
+ switch (thread_provider)
+ {
+ case thread_nspr:
+ rv = PR_JoinThread(thread);
+ break;
+ case thread_pthread:
+#if defined(_PR_PTHREADS)
+ rv = PR_SUCCESS;
+ break;
+#endif /* defined(_PR_PTHREADS) */
+ case thread_win32:
+#if defined(WIN32)
+ rv = PR_SUCCESS;
+ break;
+#endif
+ default:
+ rv = PR_FAILURE;
+ break;
+ }
+ return rv;
+} /* JoinThread */
+
+static PRStatus NewThread(
+ StartFn start, void *arg, PRThreadPriority prio, PRThreadState state)
+{
+ PRStatus rv;
+
+ switch (thread_provider)
+ {
+ case thread_nspr:
+ {
+ PRThread *thread = PR_CreateThread(
+ PR_USER_THREAD, start, arg,
+ PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
+ PR_JOINABLE_THREAD, 0);
+ rv = (NULL == thread) ? PR_FAILURE : PR_SUCCESS;
+ }
+ break;
+ case thread_pthread:
+#if defined(_PR_PTHREADS)
+ {
+ int rv;
+ pthread_t id;
+ pthread_attr_t tattr;
+ StartObject *start_object;
+ start_object = PR_NEW(StartObject);
+ PR_ASSERT(NULL != start_object);
+ start_object->start = start;
+ start_object->arg = arg;
+
+ rv = _PT_PTHREAD_ATTR_INIT(&tattr);
+ PR_ASSERT(0 == rv);
+
+ rv = pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
+ PR_ASSERT(0 == rv);
+
+ rv = pthread_attr_setstacksize(&tattr, 64 * 1024);
+ PR_ASSERT(0 == rv);
+
+ rv = _PT_PTHREAD_CREATE(&id, tattr, pthread_start, start_object);
+ (void)_PT_PTHREAD_ATTR_DESTROY(&tattr);
+ return (0 == rv) ? PR_SUCCESS : PR_FAILURE;
+ }
+#else
+ PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+ rv = PR_FAILURE;
+#endif /* defined(_PR_PTHREADS) */
+ break;
+
+ case thread_sproc:
+ PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+ rv = PR_FAILURE;
+ break;
+ case thread_win32:
+#if defined(WIN32)
+ {
+ void *th;
+ PRUintn id;
+ StartObject *start_object;
+ start_object = PR_NEW(StartObject);
+ PR_ASSERT(NULL != start_object);
+ start_object->start = start;
+ start_object->arg = arg;
+ th = (void*)_beginthreadex(
+ NULL, /* LPSECURITY_ATTRIBUTES - pointer to thread security attributes */
+ 0U, /* DWORD - initial thread stack size, in bytes */
+ windows_start, /* LPTHREAD_START_ROUTINE - pointer to thread function */
+ start_object, /* LPVOID - argument for new thread */
+ STACK_SIZE_PARAM_IS_A_RESERVATION, /*DWORD dwCreationFlags - creation flags */
+ &id /* LPDWORD - pointer to returned thread identifier */ );
+
+ rv = (NULL == th) ? PR_FAILURE : PR_SUCCESS;
+ }
+#else
+ PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+ rv = PR_FAILURE;
+#endif
+ break;
+ default:
+ PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+ rv = PR_FAILURE;
+ }
+ return rv;
+} /* NewThread */
+
+static PRStatus CreateWorker(CSServer_t *server, CSPool_t *pool)
+{
+ PRStatus rv;
+ CSWorker_t *worker = PR_NEWZAP(CSWorker_t);
+ worker->server = server;
+ PR_INIT_CLIST(&worker->element);
+ rv = NewThread(
+ Worker, worker, DEFAULT_SERVER_PRIORITY, PR_UNJOINABLE_THREAD);
+ if (PR_FAILURE == rv) {
+ PR_DELETE(worker);
+ }
+
+ TEST_LOG(cltsrv_log_file, TEST_LOG_STATUS,
+ ("\tCreateWorker(0x%p): create new worker (0x%p)\n",
+ PR_GetCurrentThread(), worker->thread));
+
+ return rv;
+} /* CreateWorker */
+
+static void PR_CALLBACK Worker(void *arg)
+{
+ PRStatus rv;
+ PRNetAddr from;
+ PRFileDesc *fd = NULL;
+ CSWorker_t *worker = (CSWorker_t*)arg;
+ CSServer_t *server = worker->server;
+ CSPool_t *pool = &server->pool;
+
+ PRThread *me = worker->thread = PR_GetCurrentThread();
+
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_NOTICE,
+ ("\t\tWorker(0x%p): started [%u]\n", me, pool->workers + 1));
+
+ PR_Lock(server->ml);
+ PR_APPEND_LINK(&worker->element, &server->list);
+ pool->workers += 1; /* define our existance */
+
+ while (cs_run == server->state)
+ {
+ while (pool->accepting >= server->workers.accepting)
+ {
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_VERBOSE,
+ ("\t\tWorker(0x%p): waiting for accept slot[%d]\n",
+ me, pool->accepting));
+ rv = PR_WaitCondVar(pool->acceptComplete, PR_INTERVAL_NO_TIMEOUT);
+ if (Aborted(rv) || (cs_run != server->state))
+ {
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_NOTICE,
+ ("\tWorker(0x%p): has been %s\n",
+ me, (Aborted(rv) ? "interrupted" : "stopped")));
+ goto exit;
+ }
+ }
+ pool->accepting += 1; /* how many are really in accept */
+ PR_Unlock(server->ml);
+
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_VERBOSE,
+ ("\t\tWorker(0x%p): calling accept\n", me));
+ fd = PR_Accept(server->listener, &from, PR_INTERVAL_NO_TIMEOUT);
+
+ PR_Lock(server->ml);
+ pool->accepting -= 1;
+ PR_NotifyCondVar(pool->acceptComplete);
+
+ if ((NULL == fd) && Aborted(PR_FAILURE))
+ {
+ if (NULL != server->listener)
+ {
+ PR_Close(server->listener);
+ server->listener = NULL;
+ }
+ goto exit;
+ }
+
+ if (NULL != fd)
+ {
+ /*
+ ** Create another worker of the total number of workers is
+ ** less than the minimum specified or we have none left in
+ ** accept() AND we're not over the maximum.
+ ** This sort of presumes that the number allowed in accept
+ ** is at least as many as the minimum. Otherwise we'll keep
+ ** creating new threads and deleting them soon after.
+ */
+ PRBool another =
+ ((pool->workers < server->workers.minimum) ||
+ ((0 == pool->accepting)
+ && (pool->workers < server->workers.maximum))) ?
+ PR_TRUE : PR_FALSE;
+ pool->active += 1;
+ PR_Unlock(server->ml);
+
+ if (another) {
+ (void)CreateWorker(server, pool);
+ }
+
+ rv = ProcessRequest(fd, server);
+ if (PR_SUCCESS != rv)
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_ERROR,
+ ("\t\tWorker(0x%p): server process ended abnormally\n", me));
+ (void)PR_Close(fd); fd = NULL;
+
+ PR_Lock(server->ml);
+ pool->active -= 1;
+ }
+ }
+
+exit:
+ PR_ClearInterrupt();
+ PR_Unlock(server->ml);
+
+ if (NULL != fd)
+ {
+ (void)PR_Shutdown(fd, PR_SHUTDOWN_BOTH);
+ (void)PR_Close(fd);
+ }
+
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_NOTICE,
+ ("\t\tWorker(0x%p): exiting [%u]\n", PR_GetCurrentThread(), pool->workers));
+
+ PR_Lock(server->ml);
+ pool->workers -= 1; /* undefine our existance */
+ PR_REMOVE_AND_INIT_LINK(&worker->element);
+ PR_NotifyCondVar(pool->exiting);
+ PR_Unlock(server->ml);
+
+ PR_DELETE(worker); /* destruction of the "worker" object */
+
+} /* Worker */
+
+static void PR_CALLBACK Server(void *arg)
+{
+ PRStatus rv;
+ PRNetAddr serverAddress;
+ CSServer_t *server = (CSServer_t*)arg;
+ PRThread *me = server->thread = PR_GetCurrentThread();
+ PRSocketOptionData sockOpt;
+
+ server->listener = PR_Socket(domain, SOCK_STREAM, protocol);
+
+ sockOpt.option = PR_SockOpt_Reuseaddr;
+ sockOpt.value.reuse_addr = PR_TRUE;
+ rv = PR_SetSocketOption(server->listener, &sockOpt);
+ TEST_ASSERT(PR_SUCCESS == rv);
+
+ memset(&serverAddress, 0, sizeof(serverAddress));
+ rv = PR_InitializeNetAddr(PR_IpAddrAny, DEFAULT_PORT, &serverAddress);
+
+ rv = PR_Bind(server->listener, &serverAddress);
+ TEST_ASSERT(PR_SUCCESS == rv);
+
+ rv = PR_Listen(server->listener, server->backlog);
+ TEST_ASSERT(PR_SUCCESS == rv);
+
+ server->started = PR_IntervalNow();
+ TimeOfDayMessage("Server started at", me);
+
+ PR_Lock(server->ml);
+ server->state = cs_run;
+ PR_NotifyCondVar(server->stateChange);
+ PR_Unlock(server->ml);
+
+ /*
+ ** Create the first worker (actually, a thread that accepts
+ ** connections and then processes the work load as needed).
+ ** From this point on, additional worker threads are created
+ ** as they are needed by existing worker threads.
+ */
+ rv = CreateWorker(server, &server->pool);
+ TEST_ASSERT(PR_SUCCESS == rv);
+
+ /*
+ ** From here on this thread is merely hanging around as the contact
+ ** point for the main test driver. It's just waiting for the driver
+ ** to declare the test complete.
+ */
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_VERBOSE,
+ ("\tServer(0x%p): waiting for state change\n", me));
+
+ PR_Lock(server->ml);
+ while ((cs_run == server->state) && !Aborted(rv))
+ {
+ rv = PR_WaitCondVar(server->stateChange, PR_INTERVAL_NO_TIMEOUT);
+ }
+ PR_Unlock(server->ml);
+ PR_ClearInterrupt();
+
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_INFO,
+ ("\tServer(0x%p): shutting down workers\n", me));
+
+ /*
+ ** Get all the worker threads to exit. They know how to
+ ** clean up after themselves, so this is just a matter of
+ ** waiting for clorine in the pool to take effect. During
+ ** this stage we're ignoring interrupts.
+ */
+ server->workers.minimum = server->workers.maximum = 0;
+
+ PR_Lock(server->ml);
+ while (!PR_CLIST_IS_EMPTY(&server->list))
+ {
+ PRCList *head = PR_LIST_HEAD(&server->list);
+ CSWorker_t *worker = (CSWorker_t*)head;
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_VERBOSE,
+ ("\tServer(0x%p): interrupting worker(0x%p)\n", me, worker));
+ rv = PR_Interrupt(worker->thread);
+ TEST_ASSERT(PR_SUCCESS == rv);
+ PR_REMOVE_AND_INIT_LINK(head);
+ }
+
+ while (server->pool.workers > 0)
+ {
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_NOTICE,
+ ("\tServer(0x%p): waiting for %u workers to exit\n",
+ me, server->pool.workers));
+ (void)PR_WaitCondVar(server->pool.exiting, PR_INTERVAL_NO_TIMEOUT);
+ }
+
+ server->state = cs_exit;
+ PR_NotifyCondVar(server->stateChange);
+ PR_Unlock(server->ml);
+
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_ALWAYS,
+ ("\tServer(0x%p): stopped after %u operations and %u bytes\n",
+ me, server->operations, server->bytesTransferred));
+
+ if (NULL != server->listener) {
+ PR_Close(server->listener);
+ }
+ server->stopped = PR_IntervalNow();
+
+} /* Server */
+
+static void WaitForCompletion(PRIntn execution)
+{
+ while (execution > 0)
+ {
+ PRIntn dally = (execution > 30) ? 30 : execution;
+ PR_Sleep(PR_SecondsToInterval(dally));
+ if (pthread_stats) {
+ PT_FPrintStats(debug_out, "\nPThread Statistics\n");
+ }
+ execution -= dally;
+ }
+} /* WaitForCompletion */
+
+static void Help(void)
+{
+ PR_fprintf(debug_out, "cltsrv test program usage:\n");
+ PR_fprintf(debug_out, "\t-a <n> threads allowed in accept (5)\n");
+ PR_fprintf(debug_out, "\t-b <n> backlock for listen (5)\n");
+ PR_fprintf(debug_out, "\t-c <threads> number of clients to create (1)\n");
+ PR_fprintf(debug_out, "\t-w <threads> minimal number of server threads (1)\n");
+ PR_fprintf(debug_out, "\t-W <threads> maximum number of server threads (1)\n");
+ PR_fprintf(debug_out, "\t-e <seconds> duration of the test in seconds (10)\n");
+ PR_fprintf(debug_out, "\t-s <string> dsn name of server (localhost)\n");
+ PR_fprintf(debug_out, "\t-G use GLOBAL threads (LOCAL)\n");
+ PR_fprintf(debug_out, "\t-T <string> thread provider ('n' | 'p' | 'w')(n)\n");
+ PR_fprintf(debug_out, "\t-X use XTP as transport (TCP)\n");
+ PR_fprintf(debug_out, "\t-6 Use IPv6 (IPv4)\n");
+ PR_fprintf(debug_out, "\t-v verbosity (accumulative) (0)\n");
+ PR_fprintf(debug_out, "\t-p pthread statistics (FALSE)\n");
+ PR_fprintf(debug_out, "\t-d debug mode (FALSE)\n");
+ PR_fprintf(debug_out, "\t-h this message\n");
+} /* Help */
+
+static Verbosity IncrementVerbosity(void)
+{
+ PRIntn verboge = (PRIntn)verbosity + 1;
+ return (Verbosity)verboge;
+} /* IncrementVerbosity */
+
+int main(int argc, char **argv)
+{
+ PRUintn index;
+ PRBool boolean;
+ CSClient_t *client;
+ PRStatus rv, joinStatus;
+ CSServer_t *server = NULL;
+ char *thread_type;
+
+ PRUintn backlog = DEFAULT_BACKLOG;
+ PRUintn clients = DEFAULT_CLIENTS;
+ const char *serverName = DEFAULT_SERVER;
+ PRBool serverIsLocal = PR_TRUE;
+ PRUintn accepting = ALLOWED_IN_ACCEPT;
+ PRUintn workersMin = DEFAULT_WORKERS_MIN;
+ PRUintn workersMax = DEFAULT_WORKERS_MAX;
+ PRIntn execution = DEFAULT_EXECUTION_TIME;
+
+ /*
+ * -G use global threads
+ * -a <n> threads allowed in accept
+ * -b <n> backlock for listen
+ * -c <threads> number of clients to create
+ * -w <threads> minimal number of server threads
+ * -W <threads> maximum number of server threads
+ * -e <seconds> duration of the test in seconds
+ * -s <string> dsn name of server (implies no server here)
+ * -v verbosity
+ */
+
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "GX6b:a:c:w:W:e:s:T:vdhp");
+
+#if defined(WIN32)
+ thread_provider = thread_win32;
+#elif defined(_PR_PTHREADS)
+ thread_provider = thread_pthread;
+#else
+ thread_provider = thread_nspr;
+#endif
+
+ debug_out = PR_GetSpecialFD(PR_StandardError);
+
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 'G': /* use global threads */
+ thread_scope = PR_GLOBAL_THREAD;
+ break;
+ case 'X': /* use XTP as transport */
+ protocol = 36;
+ break;
+ case '6': /* Use IPv6 */
+ domain = PR_AF_INET6;
+ break;
+ case 'a': /* the value for accepting */
+ accepting = atoi(opt->value);
+ break;
+ case 'b': /* the value for backlock */
+ backlog = atoi(opt->value);
+ break;
+ case 'T': /* the thread provider */
+ if ('n' == *opt->value) {
+ thread_provider = thread_nspr;
+ }
+ else if ('p' == *opt->value) {
+ thread_provider = thread_pthread;
+ }
+ else if ('w' == *opt->value) {
+ thread_provider = thread_win32;
+ }
+ else {
+ Help();
+ return 2;
+ }
+ break;
+ case 'c': /* number of client threads */
+ clients = atoi(opt->value);
+ break;
+ case 'w': /* minimum server worker threads */
+ workersMin = atoi(opt->value);
+ break;
+ case 'W': /* maximum server worker threads */
+ workersMax = atoi(opt->value);
+ break;
+ case 'e': /* program execution time in seconds */
+ execution = atoi(opt->value);
+ break;
+ case 's': /* server's address */
+ serverName = opt->value;
+ break;
+ case 'v': /* verbosity */
+ verbosity = IncrementVerbosity();
+ break;
+ case 'd': /* debug mode */
+ debug_mode = PR_TRUE;
+ break;
+ case 'p': /* pthread mode */
+ pthread_stats = PR_TRUE;
+ break;
+ case 'h':
+ default:
+ Help();
+ return 2;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ if (0 != PL_strcmp(serverName, DEFAULT_SERVER)) {
+ serverIsLocal = PR_FALSE;
+ }
+ if (0 == execution) {
+ execution = DEFAULT_EXECUTION_TIME;
+ }
+ if (0 == workersMax) {
+ workersMax = DEFAULT_WORKERS_MAX;
+ }
+ if (0 == workersMin) {
+ workersMin = DEFAULT_WORKERS_MIN;
+ }
+ if (0 == accepting) {
+ accepting = ALLOWED_IN_ACCEPT;
+ }
+ if (0 == backlog) {
+ backlog = DEFAULT_BACKLOG;
+ }
+
+ if (workersMin > accepting) {
+ accepting = workersMin;
+ }
+
+ PR_STDIO_INIT();
+ TimeOfDayMessage("Client/Server started at", PR_GetCurrentThread());
+
+ cltsrv_log_file = PR_NewLogModule("cltsrv_log");
+ MY_ASSERT(NULL != cltsrv_log_file);
+ boolean = PR_SetLogFile("cltsrv.log");
+ MY_ASSERT(boolean);
+
+ if (serverIsLocal)
+ {
+ /* Establish the server */
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_INFO,
+ ("main(0x%p): starting server\n", PR_GetCurrentThread()));
+
+ server = PR_NEWZAP(CSServer_t);
+ PR_INIT_CLIST(&server->list);
+ server->state = cs_init;
+ server->ml = PR_NewLock();
+ server->backlog = backlog;
+ server->port = DEFAULT_PORT;
+ server->workers.minimum = workersMin;
+ server->workers.maximum = workersMax;
+ server->workers.accepting = accepting;
+ server->stateChange = PR_NewCondVar(server->ml);
+ server->pool.exiting = PR_NewCondVar(server->ml);
+ server->pool.acceptComplete = PR_NewCondVar(server->ml);
+
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_NOTICE,
+ ("main(0x%p): creating server thread\n", PR_GetCurrentThread()));
+
+ rv = NewThread(
+ Server, server, PR_PRIORITY_HIGH, PR_JOINABLE_THREAD);
+ TEST_ASSERT(PR_SUCCESS == rv);
+
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_VERBOSE,
+ ("main(0x%p): waiting for server init\n", PR_GetCurrentThread()));
+
+ PR_Lock(server->ml);
+ while (server->state == cs_init) {
+ PR_WaitCondVar(server->stateChange, PR_INTERVAL_NO_TIMEOUT);
+ }
+ PR_Unlock(server->ml);
+
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_VERBOSE,
+ ("main(0x%p): server init complete (port #%d)\n",
+ PR_GetCurrentThread(), server->port));
+ }
+
+ if (clients != 0)
+ {
+ /* Create all of the clients */
+ PRHostEnt host;
+ char buffer[BUFFER_SIZE];
+ client = (CSClient_t*)PR_CALLOC(clients * sizeof(CSClient_t));
+
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_VERBOSE,
+ ("main(0x%p): creating %d client threads\n",
+ PR_GetCurrentThread(), clients));
+
+ if (!serverIsLocal)
+ {
+ rv = PR_GetHostByName(serverName, buffer, BUFFER_SIZE, &host);
+ if (PR_SUCCESS != rv)
+ {
+ PL_FPrintError(PR_STDERR, "PR_GetHostByName");
+ return 2;
+ }
+ }
+
+ for (index = 0; index < clients; ++index)
+ {
+ client[index].state = cs_init;
+ client[index].ml = PR_NewLock();
+ if (serverIsLocal)
+ {
+ (void)PR_InitializeNetAddr(
+ PR_IpAddrLoopback, DEFAULT_PORT,
+ &client[index].serverAddress);
+ }
+ else
+ {
+ (void)PR_EnumerateHostEnt(
+ 0, &host, DEFAULT_PORT, &client[index].serverAddress);
+ }
+ client[index].stateChange = PR_NewCondVar(client[index].ml);
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_INFO,
+ ("main(0x%p): creating client threads\n", PR_GetCurrentThread()));
+ rv = NewThread(
+ Client, &client[index], PR_PRIORITY_NORMAL, PR_JOINABLE_THREAD);
+ TEST_ASSERT(PR_SUCCESS == rv);
+ PR_Lock(client[index].ml);
+ while (cs_init == client[index].state) {
+ PR_WaitCondVar(client[index].stateChange, PR_INTERVAL_NO_TIMEOUT);
+ }
+ PR_Unlock(client[index].ml);
+ }
+ }
+
+ /* Then just let them go at it for a bit */
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_ALWAYS,
+ ("main(0x%p): waiting for execution interval (%d seconds)\n",
+ PR_GetCurrentThread(), execution));
+
+ WaitForCompletion(execution);
+
+ TimeOfDayMessage("Shutting down", PR_GetCurrentThread());
+
+ if (clients != 0)
+ {
+ for (index = 0; index < clients; ++index)
+ {
+ TEST_LOG(cltsrv_log_file, TEST_LOG_STATUS,
+ ("main(0x%p): notifying client(0x%p) to stop\n",
+ PR_GetCurrentThread(), client[index].thread));
+
+ PR_Lock(client[index].ml);
+ if (cs_run == client[index].state)
+ {
+ client[index].state = cs_stop;
+ PR_Interrupt(client[index].thread);
+ while (cs_stop == client[index].state)
+ PR_WaitCondVar(
+ client[index].stateChange, PR_INTERVAL_NO_TIMEOUT);
+ }
+ PR_Unlock(client[index].ml);
+
+ TEST_LOG(cltsrv_log_file, TEST_LOG_VERBOSE,
+ ("main(0x%p): joining client(0x%p)\n",
+ PR_GetCurrentThread(), client[index].thread));
+
+ joinStatus = JoinThread(client[index].thread);
+ TEST_ASSERT(PR_SUCCESS == joinStatus);
+ PR_DestroyCondVar(client[index].stateChange);
+ PR_DestroyLock(client[index].ml);
+ }
+ PR_DELETE(client);
+ }
+
+ if (NULL != server)
+ {
+ /* All clients joined - retrieve the server */
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_NOTICE,
+ ("main(0x%p): notifying server(0x%p) to stop\n",
+ PR_GetCurrentThread(), server->thread));
+
+ PR_Lock(server->ml);
+ server->state = cs_stop;
+ PR_Interrupt(server->thread);
+ while (cs_exit != server->state) {
+ PR_WaitCondVar(server->stateChange, PR_INTERVAL_NO_TIMEOUT);
+ }
+ PR_Unlock(server->ml);
+
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_NOTICE,
+ ("main(0x%p): joining server(0x%p)\n",
+ PR_GetCurrentThread(), server->thread));
+ joinStatus = JoinThread(server->thread);
+ TEST_ASSERT(PR_SUCCESS == joinStatus);
+
+ PR_DestroyCondVar(server->stateChange);
+ PR_DestroyCondVar(server->pool.exiting);
+ PR_DestroyCondVar(server->pool.acceptComplete);
+ PR_DestroyLock(server->ml);
+ PR_DELETE(server);
+ }
+
+ TEST_LOG(
+ cltsrv_log_file, TEST_LOG_ALWAYS,
+ ("main(0x%p): test complete\n", PR_GetCurrentThread()));
+
+ if (thread_provider == thread_win32) {
+ thread_type = "\nWin32 Thread Statistics\n";
+ }
+ else if (thread_provider == thread_pthread) {
+ thread_type = "\npthread Statistics\n";
+ }
+ else if (thread_provider == thread_sproc) {
+ thread_type = "\nsproc Statistics\n";
+ }
+ else {
+ PR_ASSERT(thread_provider == thread_nspr);
+ thread_type = "\nPRThread Statistics\nn";
+ }
+
+ PT_FPrintStats(debug_out, thread_type);
+
+ TimeOfDayMessage("Test exiting at", PR_GetCurrentThread());
+ PR_Cleanup();
+ return 0;
+} /* main */
+
+/* cltsrv.c */
diff --git a/nsprpub/pr/tests/prpoll.c b/nsprpub/pr/tests/prpoll.c
new file mode 100644
index 0000000000..5c87a57d17
--- /dev/null
+++ b/nsprpub/pr/tests/prpoll.c
@@ -0,0 +1,351 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#ifdef XP_UNIX
+#include <unistd.h> /* for close() */
+#endif
+
+#include "prinit.h"
+#include "prio.h"
+#include "prlog.h"
+#include "prprf.h"
+#include "prnetdb.h"
+
+#include "private/pprio.h"
+
+#define CLIENT_LOOPS 5
+#define BUF_SIZE 128
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#ifdef WINCE
+
+int main(int argc, char **argv)
+{
+ fprintf(stderr, "Invalid/Broken Test for WinCE/WinMobile\n");
+ exit(1);
+}
+
+#else
+
+static void
+clientThreadFunc(void *arg)
+{
+ PRUint16 port = (PRUint16) arg;
+ PRFileDesc *sock;
+ PRNetAddr addr;
+ char buf[BUF_SIZE];
+ int i;
+
+ addr.inet.family = PR_AF_INET;
+ addr.inet.port = PR_htons(port);
+ addr.inet.ip = PR_htonl(PR_INADDR_LOOPBACK);
+ PR_snprintf(buf, sizeof(buf), "%hu", port);
+
+ for (i = 0; i < 5; i++) {
+ sock = PR_NewTCPSocket();
+ PR_Connect(sock, &addr, PR_INTERVAL_NO_TIMEOUT);
+
+ PR_Write(sock, buf, sizeof(buf));
+ PR_Close(sock);
+ }
+}
+
+int main(int argc, char **argv)
+{
+ PRFileDesc *listenSock1, *listenSock2;
+ PRFileDesc *badFD;
+ PRUint16 listenPort1, listenPort2;
+ PRNetAddr addr;
+ char buf[BUF_SIZE];
+ PRThread *clientThread;
+ PRPollDesc pds0[10], pds1[10], *pds, *other_pds;
+ PRIntn npds;
+ PRInt32 retVal;
+ PRInt32 rv;
+ PROsfd sd;
+ struct sockaddr_in saddr;
+ PRIntn saddr_len;
+ PRUint16 listenPort3;
+ PRFileDesc *socket_poll_fd;
+ PRIntn i, j;
+
+ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
+ PR_STDIO_INIT();
+
+ printf("This program tests PR_Poll with sockets.\n");
+ printf("Timeout, error reporting, and normal operation are tested.\n\n");
+
+ /* Create two listening sockets */
+ if ((listenSock1 = PR_NewTCPSocket()) == NULL) {
+ fprintf(stderr, "Can't create a new TCP socket\n");
+ exit(1);
+ }
+ addr.inet.family = PR_AF_INET;
+ addr.inet.ip = PR_htonl(PR_INADDR_ANY);
+ addr.inet.port = PR_htons(0);
+ if (PR_Bind(listenSock1, &addr) == PR_FAILURE) {
+ fprintf(stderr, "Can't bind socket\n");
+ exit(1);
+ }
+ if (PR_GetSockName(listenSock1, &addr) == PR_FAILURE) {
+ fprintf(stderr, "PR_GetSockName failed\n");
+ exit(1);
+ }
+ listenPort1 = PR_ntohs(addr.inet.port);
+ if (PR_Listen(listenSock1, 5) == PR_FAILURE) {
+ fprintf(stderr, "Can't listen on a socket\n");
+ exit(1);
+ }
+
+ if ((listenSock2 = PR_NewTCPSocket()) == NULL) {
+ fprintf(stderr, "Can't create a new TCP socket\n");
+ exit(1);
+ }
+ addr.inet.family = PR_AF_INET;
+ addr.inet.ip = PR_htonl(PR_INADDR_ANY);
+ addr.inet.port = PR_htons(0);
+ if (PR_Bind(listenSock2, &addr) == PR_FAILURE) {
+ fprintf(stderr, "Can't bind socket\n");
+ exit(1);
+ }
+ if (PR_GetSockName(listenSock2, &addr) == PR_FAILURE) {
+ fprintf(stderr, "PR_GetSockName failed\n");
+ exit(1);
+ }
+ listenPort2 = PR_ntohs(addr.inet.port);
+ if (PR_Listen(listenSock2, 5) == PR_FAILURE) {
+ fprintf(stderr, "Can't listen on a socket\n");
+ exit(1);
+ }
+ /* Set up the poll descriptor array */
+ pds = pds0;
+ other_pds = pds1;
+ memset(pds, 0, sizeof(pds));
+ npds = 0;
+ pds[npds].fd = listenSock1;
+ pds[npds].in_flags = PR_POLL_READ;
+ npds++;
+ pds[npds].fd = listenSock2;
+ pds[npds].in_flags = PR_POLL_READ;
+ npds++;
+
+ sd = socket(AF_INET, SOCK_STREAM, 0);
+ PR_ASSERT(sd >= 0);
+ memset((char *) &saddr, 0, sizeof(saddr));
+ saddr.sin_family = AF_INET;
+ saddr.sin_addr.s_addr = htonl(INADDR_ANY);
+ saddr.sin_port = htons(0);
+
+ rv = bind(sd, (struct sockaddr *)&saddr, sizeof(saddr));
+ PR_ASSERT(rv == 0);
+ saddr_len = sizeof(saddr);
+ rv = getsockname(sd, (struct sockaddr *) &saddr, &saddr_len);
+ PR_ASSERT(rv == 0);
+ listenPort3 = ntohs(saddr.sin_port);
+
+ rv = listen(sd, 5);
+ PR_ASSERT(rv == 0);
+ pds[npds].fd = socket_poll_fd = PR_CreateSocketPollFd(sd);
+ PR_ASSERT(pds[npds].fd);
+ pds[npds].in_flags = PR_POLL_READ;
+ npds++;
+ PR_snprintf(buf, sizeof(buf),
+ "The server thread is listening on ports %hu, %hu and %hu\n\n",
+ listenPort1, listenPort2, listenPort3);
+ printf("%s", buf);
+
+ /* Testing timeout */
+ printf("PR_Poll should time out in 5 seconds\n");
+ retVal = PR_Poll(pds, npds, PR_SecondsToInterval(5));
+ if (retVal != 0) {
+ PR_snprintf(buf, sizeof(buf),
+ "PR_Poll should time out and return 0, but it returns %ld\n",
+ retVal);
+ fprintf(stderr, "%s", buf);
+ exit(1);
+ }
+ printf("PR_Poll timed out. Test passed.\n\n");
+
+ /* Testing bad fd */
+ printf("PR_Poll should detect a bad file descriptor\n");
+ if ((badFD = PR_NewTCPSocket()) == NULL) {
+ fprintf(stderr, "Can't create a TCP socket\n");
+ exit(1);
+ }
+
+ pds[npds].fd = badFD;
+ pds[npds].in_flags = PR_POLL_READ;
+ npds++;
+ PR_Close(badFD); /* make the fd bad */
+#if 0
+ retVal = PR_Poll(pds, npds, PR_INTERVAL_NO_TIMEOUT);
+ if (retVal != 1 || (unsigned short) pds[2].out_flags != PR_POLL_NVAL) {
+ fprintf(stderr, "Failed to detect the bad fd: "
+ "PR_Poll returns %d, out_flags is 0x%hx\n",
+ retVal, pds[npds - 1].out_flags);
+ exit(1);
+ }
+ printf("PR_Poll detected the bad fd. Test passed.\n\n");
+#endif
+ npds--;
+
+ clientThread = PR_CreateThread(PR_USER_THREAD,
+ clientThreadFunc, (void *) listenPort1,
+ PR_PRIORITY_NORMAL, PR_LOCAL_THREAD,
+ PR_UNJOINABLE_THREAD, 0);
+ if (clientThread == NULL) {
+ fprintf(stderr, "can't create thread\n");
+ exit(1);
+ }
+
+ clientThread = PR_CreateThread(PR_USER_THREAD,
+ clientThreadFunc, (void *) listenPort2,
+ PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
+ PR_UNJOINABLE_THREAD, 0);
+ if (clientThread == NULL) {
+ fprintf(stderr, "can't create thread\n");
+ exit(1);
+ }
+
+ clientThread = PR_CreateThread(PR_USER_THREAD,
+ clientThreadFunc, (void *) listenPort3,
+ PR_PRIORITY_NORMAL, PR_GLOBAL_BOUND_THREAD,
+ PR_UNJOINABLE_THREAD, 0);
+ if (clientThread == NULL) {
+ fprintf(stderr, "can't create thread\n");
+ exit(1);
+ }
+
+
+ printf("Three client threads are created. Each of them will\n");
+ printf("send data to one of the three ports the server is listening on.\n");
+ printf("The data they send is the port number. Each of them send\n");
+ printf("the data five times, so you should see ten lines below,\n");
+ printf("interleaved in an arbitrary order.\n");
+
+ /* 30 events total */
+ i = 0;
+ while (i < 30) {
+ PRPollDesc *tmp;
+ int nextIndex;
+ int nEvents = 0;
+
+ retVal = PR_Poll(pds, npds, PR_INTERVAL_NO_TIMEOUT);
+ PR_ASSERT(retVal != 0); /* no timeout */
+ if (retVal == -1) {
+ fprintf(stderr, "PR_Poll failed\n");
+ exit(1);
+ }
+
+ nextIndex = 3;
+ /* the three listening sockets */
+ for (j = 0; j < 3; j++) {
+ other_pds[j] = pds[j];
+ PR_ASSERT((pds[j].out_flags & PR_POLL_WRITE) == 0
+ && (pds[j].out_flags & PR_POLL_EXCEPT) == 0);
+ if (pds[j].out_flags & PR_POLL_READ) {
+ PRFileDesc *sock;
+
+ nEvents++;
+ if (j == 2) {
+ PROsfd newsd;
+ newsd = accept(PR_FileDesc2NativeHandle(pds[j].fd), NULL, 0);
+ if (newsd == -1) {
+ fprintf(stderr, "accept() failed\n");
+ exit(1);
+ }
+ other_pds[nextIndex].fd = PR_CreateSocketPollFd(newsd);
+ PR_ASSERT(other_pds[nextIndex].fd);
+ other_pds[nextIndex].in_flags = PR_POLL_READ;
+ } else {
+ sock = PR_Accept(pds[j].fd, NULL, PR_INTERVAL_NO_TIMEOUT);
+ if (sock == NULL) {
+ fprintf(stderr, "PR_Accept() failed\n");
+ exit(1);
+ }
+ other_pds[nextIndex].fd = sock;
+ other_pds[nextIndex].in_flags = PR_POLL_READ;
+ }
+ nextIndex++;
+ } else if (pds[j].out_flags & PR_POLL_ERR) {
+ fprintf(stderr, "PR_Poll() indicates that an fd has error\n");
+ exit(1);
+ } else if (pds[j].out_flags & PR_POLL_NVAL) {
+ fprintf(stderr, "PR_Poll() indicates that fd %d is invalid\n",
+ PR_FileDesc2NativeHandle(pds[j].fd));
+ exit(1);
+ }
+ }
+
+ for (j = 3; j < npds; j++) {
+ PR_ASSERT((pds[j].out_flags & PR_POLL_WRITE) == 0
+ && (pds[j].out_flags & PR_POLL_EXCEPT) == 0);
+ if (pds[j].out_flags & PR_POLL_READ) {
+ PRInt32 nBytes;
+
+ nEvents++;
+ /* XXX: This call is a hack and should be fixed */
+ if (PR_GetDescType(pds[j].fd) == (PRDescType) 0) {
+ nBytes = recv(PR_FileDesc2NativeHandle(pds[j].fd), buf,
+ sizeof(buf), 0);
+ if (nBytes == -1) {
+ fprintf(stderr, "recv() failed\n");
+ exit(1);
+ }
+ printf("Server read %d bytes from native fd %d\n",nBytes,
+ PR_FileDesc2NativeHandle(pds[j].fd));
+#ifdef WIN32
+ closesocket((SOCKET)PR_FileDesc2NativeHandle(pds[j].fd));
+#else
+ close(PR_FileDesc2NativeHandle(pds[j].fd));
+#endif
+ PR_DestroySocketPollFd(pds[j].fd);
+ } else {
+ nBytes = PR_Read(pds[j].fd, buf, sizeof(buf));
+ if (nBytes == -1) {
+ fprintf(stderr, "PR_Read() failed\n");
+ exit(1);
+ }
+ PR_Close(pds[j].fd);
+ }
+ /* Just to be safe */
+ buf[BUF_SIZE - 1] = '\0';
+ printf("The server received \"%s\" from a client\n", buf);
+ } else if (pds[j].out_flags & PR_POLL_ERR) {
+ fprintf(stderr, "PR_Poll() indicates that an fd has error\n");
+ exit(1);
+ } else if (pds[j].out_flags & PR_POLL_NVAL) {
+ fprintf(stderr, "PR_Poll() indicates that an fd is invalid\n");
+ exit(1);
+ } else {
+ other_pds[nextIndex] = pds[j];
+ nextIndex++;
+ }
+ }
+
+ PR_ASSERT(retVal == nEvents);
+ /* swap */
+ tmp = pds;
+ pds = other_pds;
+ other_pds = tmp;
+ npds = nextIndex;
+ i += nEvents;
+ }
+ PR_DestroySocketPollFd(socket_poll_fd);
+
+ printf("All tests finished\n");
+ PR_Cleanup();
+ return 0;
+}
+
+
+#endif /* ifdef WINCE */
diff --git a/nsprpub/pr/tests/prpollml.c b/nsprpub/pr/tests/prpollml.c
new file mode 100644
index 0000000000..118d3674df
--- /dev/null
+++ b/nsprpub/pr/tests/prpollml.c
@@ -0,0 +1,136 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * This test exercises the code that allocates and frees the syspoll_list
+ * array of PRThread in the pthreads version. This test is intended to be
+ * run under Purify to verify that there is no memory leak.
+ */
+
+#include "nspr.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define POLL_DESC_COUNT 256 /* This should be greater than the
+ * STACK_POLL_DESC_COUNT macro in
+ * ptio.c to cause syspoll_list to
+ * be created. */
+
+static PRPollDesc pd[POLL_DESC_COUNT];
+
+static void Test(void)
+{
+ int i;
+ PRInt32 rv;
+ PRIntervalTime timeout;
+
+ timeout = PR_MillisecondsToInterval(10);
+ /* cause syspoll_list to grow */
+ for (i = 1; i <= POLL_DESC_COUNT; i++) {
+ rv = PR_Poll(pd, i, timeout);
+ if (rv != 0) {
+ fprintf(stderr,
+ "PR_Poll should time out but returns %d (%d, %d)\n",
+ (int) rv, (int) PR_GetError(), (int) PR_GetOSError());
+ exit(1);
+ }
+ }
+ /* syspoll_list should be large enough for all these */
+ for (i = POLL_DESC_COUNT; i >= 1; i--) {
+ rv = PR_Poll(pd, i, timeout);
+ if (rv != 0) {
+ fprintf(stderr, "PR_Poll should time out but returns %d\n",
+ (int) rv);
+ exit(1);
+ }
+ }
+}
+
+static void ThreadFunc(void *arg)
+{
+ Test();
+}
+
+int main(int argc, char **argv)
+{
+ int i;
+ PRThread *thread;
+ PRFileDesc *sock;
+ PRNetAddr addr;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.inet.family = PR_AF_INET;
+ addr.inet.port = PR_htons(0);
+ addr.inet.ip = PR_htonl(PR_INADDR_ANY);
+ for (i = 0; i < POLL_DESC_COUNT; i++) {
+ sock = PR_NewTCPSocket();
+ if (sock == NULL) {
+ fprintf(stderr, "PR_NewTCPSocket failed (%d, %d)\n",
+ (int) PR_GetError(), (int) PR_GetOSError());
+ fprintf(stderr, "Ensure the per process file descriptor limit "
+ "is greater than %d.", POLL_DESC_COUNT);
+ exit(1);
+ }
+ if (PR_Bind(sock, &addr) == PR_FAILURE) {
+ fprintf(stderr, "PR_Bind failed (%d, %d)\n",
+ (int) PR_GetError(), (int) PR_GetOSError());
+ exit(1);
+ }
+ if (PR_Listen(sock, 5) == PR_FAILURE) {
+ fprintf(stderr, "PR_Listen failed (%d, %d)\n",
+ (int) PR_GetError(), (int) PR_GetOSError());
+ exit(1);
+ }
+
+ pd[i].fd = sock;
+ pd[i].in_flags = PR_POLL_READ;
+ }
+
+ /* first run the test on the primordial thread */
+ Test();
+
+ /* then run the test on all three kinds of threads */
+ thread = PR_CreateThread(PR_USER_THREAD, ThreadFunc, NULL,
+ PR_PRIORITY_NORMAL, PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0);
+ if (NULL == thread) {
+ fprintf(stderr, "PR_CreateThread failed\n");
+ exit(1);
+ }
+ if (PR_JoinThread(thread) == PR_FAILURE) {
+ fprintf(stderr, "PR_JoinThread failed\n");
+ exit(1);
+ }
+ thread = PR_CreateThread(PR_USER_THREAD, ThreadFunc, NULL,
+ PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0);
+ if (NULL == thread) {
+ fprintf(stderr, "PR_CreateThread failed\n");
+ exit(1);
+ }
+ if (PR_JoinThread(thread) == PR_FAILURE) {
+ fprintf(stderr, "PR_JoinThread failed\n");
+ exit(1);
+ }
+ thread = PR_CreateThread(PR_USER_THREAD, ThreadFunc, NULL,
+ PR_PRIORITY_NORMAL, PR_GLOBAL_BOUND_THREAD, PR_JOINABLE_THREAD, 0);
+ if (NULL == thread) {
+ fprintf(stderr, "PR_CreateThread failed\n");
+ exit(1);
+ }
+ if (PR_JoinThread(thread) == PR_FAILURE) {
+ fprintf(stderr, "PR_JoinThread failed\n");
+ exit(1);
+ }
+ for (i = 0; i < POLL_DESC_COUNT; i++) {
+ if (PR_Close(pd[i].fd) == PR_FAILURE) {
+ fprintf(stderr, "PR_Close failed\n");
+ exit(1);
+ }
+ }
+ PR_Cleanup();
+ printf("PASS\n");
+ return 0;
+}
diff --git a/nsprpub/pr/tests/prselect.c b/nsprpub/pr/tests/prselect.c
new file mode 100644
index 0000000000..2a81100e87
--- /dev/null
+++ b/nsprpub/pr/tests/prselect.c
@@ -0,0 +1,368 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/***********************************************************************
+** 1997 - Netscape Communications Corporation
+**
+** Name: prselect_err.c
+**
+** Description: tests PR_Select with sockets Error condition functions.
+**
+** Modification History:
+** 14-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
+** The debug mode will print all of the printfs associated with this test.
+** The regress mode will be the default mode. Since the regress tool limits
+** the output to a one line status:PASS or FAIL,all of the printf statements
+** have been handled with an if (debug_mode) statement.
+***********************************************************************/
+
+/***********************************************************************
+** Includes
+***********************************************************************/
+/* Used to get the command line option */
+#include "plgetopt.h"
+#include "prttools.h"
+
+
+#include "prinit.h"
+#include "prio.h"
+#include "prlog.h"
+#include "prprf.h"
+#include "prerror.h"
+#include "prnetdb.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+/***********************************************************************
+** PRIVATE FUNCTION: Test_Result
+** DESCRIPTION: Used in conjunction with the regress tool, prints out the
+** status of the test case.
+** INPUTS: PASS/FAIL
+** OUTPUTS: None
+** RETURN: None
+** SIDE EFFECTS:
+**
+** RESTRICTIONS:
+** None
+** MEMORY: NA
+** ALGORITHM: Determine what the status is and print accordingly.
+**
+***********************************************************************/
+
+
+static Test_Result (int result)
+{
+ if (result == PASS) {
+ printf ("PASS\n");
+ }
+ else {
+ printf ("FAIL\n");
+ }
+}
+
+static void
+clientThreadFunc(void *arg)
+{
+ PRUint16 port = (PRUint16) arg;
+ PRFileDesc *sock;
+ PRNetAddr addr;
+ char buf[128];
+ int i;
+
+ addr.inet.family = AF_INET;
+ addr.inet.port = PR_htons(port);
+ addr.inet.ip = PR_htonl(INADDR_LOOPBACK);
+ PR_snprintf(buf, sizeof(buf), "%hu", port);
+
+ for (i = 0; i < 5; i++) {
+ sock = PR_NewTCPSocket();
+ PR_Connect(sock, &addr, PR_INTERVAL_NO_TIMEOUT);
+ PR_Write(sock, buf, sizeof(buf));
+ PR_Close(sock);
+ }
+}
+
+int main(int argc, char **argv)
+{
+ PRFileDesc *listenSock1, *listenSock2;
+ PRFileDesc *badFD;
+ PRFileDesc *fds0[10], *fds1[10], **fds, **other_fds;
+ PRIntn nfds;
+ PRUint16 listenPort1, listenPort2;
+ PRNetAddr addr;
+ PR_fd_set readFdSet;
+ char buf[128];
+ PRThread *clientThread;
+ PRInt32 retVal;
+ PRIntn i, j;
+
+ /* The command line argument: -d is used to determine if the test is being run
+ in debug mode. The regress tool requires only one line output:PASS or FAIL.
+ All of the printfs associated with this test has been handled with a if (debug_mode)
+ test.
+ Usage: test_name -d
+ */
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "d:");
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 'd': /* debug mode */
+ debug_mode = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ /* main test */
+
+ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
+ PR_STDIO_INIT();
+
+ if (debug_mode) {
+ printf("This program tests PR_Select with sockets. Timeout, error\n");
+ printf("reporting, and normal operation are tested.\n\n");
+ }
+
+ /* Create two listening sockets */
+ if ((listenSock1 = PR_NewTCPSocket()) == NULL) {
+ fprintf(stderr, "Can't create a new TCP socket\n");
+ if (!debug_mode) {
+ Test_Result(FAIL);
+ }
+ exit(1);
+ }
+ addr.inet.family = AF_INET;
+ addr.inet.ip = PR_htonl(INADDR_ANY);
+ addr.inet.port = PR_htons(0);
+ if (PR_Bind(listenSock1, &addr) == PR_FAILURE) {
+ fprintf(stderr, "Can't bind socket\n");
+ if (!debug_mode) {
+ Test_Result(FAIL);
+ }
+ exit(1);
+ }
+ if (PR_GetSockName(listenSock1, &addr) == PR_FAILURE) {
+ fprintf(stderr, "PR_GetSockName failed\n");
+ if (!debug_mode) {
+ Test_Result(FAIL);
+ }
+ exit(1);
+ }
+ listenPort1 = PR_ntohs(addr.inet.port);
+ if (PR_Listen(listenSock1, 5) == PR_FAILURE) {
+ fprintf(stderr, "Can't listen on a socket\n");
+ if (!debug_mode) {
+ Test_Result(FAIL);
+ }
+ exit(1);
+ }
+
+ if ((listenSock2 = PR_NewTCPSocket()) == NULL) {
+ fprintf(stderr, "Can't create a new TCP socket\n");
+ if (!debug_mode) {
+ Test_Result(FAIL);
+ }
+ exit(1);
+ }
+ addr.inet.family = AF_INET;
+ addr.inet.ip = PR_htonl(INADDR_ANY);
+ addr.inet.port = PR_htons(0);
+ if (PR_Bind(listenSock2, &addr) == PR_FAILURE) {
+ fprintf(stderr, "Can't bind socket\n");
+ if (!debug_mode) {
+ Test_Result(FAIL);
+ }
+ exit(1);
+ }
+ if (PR_GetSockName(listenSock2, &addr) == PR_FAILURE) {
+ fprintf(stderr, "PR_GetSockName failed\n");
+ if (!debug_mode) {
+ Test_Result(FAIL);
+ }
+ exit(1);
+ }
+ listenPort2 = PR_ntohs(addr.inet.port);
+ if (PR_Listen(listenSock2, 5) == PR_FAILURE) {
+ fprintf(stderr, "Can't listen on a socket\n");
+ if (!debug_mode) {
+ Test_Result(FAIL);
+ }
+ exit(1);
+ }
+ PR_snprintf(buf, sizeof(buf),
+ "The server thread is listening on ports %hu and %hu\n\n",
+ listenPort1, listenPort2);
+ printf("%s", buf);
+
+ /* Set up the fd set */
+ PR_FD_ZERO(&readFdSet);
+ PR_FD_SET(listenSock1, &readFdSet);
+ PR_FD_SET(listenSock2, &readFdSet);
+
+ /* Testing timeout */
+ if (debug_mode) {
+ printf("PR_Select should time out in 5 seconds\n");
+ }
+ retVal = PR_Select(0 /* unused */, &readFdSet, NULL, NULL,
+ PR_SecondsToInterval(5));
+ if (retVal != 0) {
+ PR_snprintf(buf, sizeof(buf),
+ "PR_Select should time out and return 0, but it returns %ld\n",
+ retVal);
+ fprintf(stderr, "%s", buf);
+ if (retVal == -1) {
+ fprintf(stderr, "Error %d, oserror %d\n", PR_GetError(),
+ PR_GetOSError());
+ if (!debug_mode) {
+ Test_Result(FAIL);
+ }
+ }
+ exit(1);
+ }
+ if (debug_mode) {
+ printf("PR_Select timed out. Test passed.\n\n");
+ }
+ else {
+ Test_Result(PASS);
+ }
+
+ /* Testing bad fd */
+ printf("PR_Select should detect a bad file descriptor\n");
+ if ((badFD = PR_NewTCPSocket()) == NULL) {
+ fprintf(stderr, "Can't create a TCP socket\n");
+ exit(1);
+ }
+
+ PR_FD_SET(listenSock1, &readFdSet);
+ PR_FD_SET(listenSock2, &readFdSet);
+ PR_FD_SET(badFD, &readFdSet);
+ PR_Close(badFD); /* make the fd bad */
+ retVal = PR_Select(0 /* unused */, &readFdSet, NULL, NULL,
+ PR_INTERVAL_NO_TIMEOUT);
+ if (retVal != -1 || PR_GetError() != PR_BAD_DESCRIPTOR_ERROR) {
+ fprintf(stderr, "Failed to detect the bad fd: "
+ "PR_Select returns %d\n", retVal);
+ if (retVal == -1) {
+ fprintf(stderr, "Error %d, oserror %d\n", PR_GetError(),
+ PR_GetOSError());
+ }
+ exit(1);
+ }
+ printf("PR_Select detected a bad fd. Test passed.\n\n");
+ PR_FD_CLR(badFD, &readFdSet);
+
+ clientThread = PR_CreateThread(PR_USER_THREAD,
+ clientThreadFunc, (void *) listenPort1,
+ PR_PRIORITY_NORMAL, PR_LOCAL_THREAD,
+ PR_UNJOINABLE_THREAD, 0);
+ if (clientThread == NULL) {
+ fprintf(stderr, "can't create thread\n");
+ exit(1);
+ }
+
+ clientThread = PR_CreateThread(PR_USER_THREAD,
+ clientThreadFunc, (void *) listenPort2,
+ PR_PRIORITY_NORMAL, PR_LOCAL_THREAD,
+ PR_UNJOINABLE_THREAD, 0);
+ if (clientThread == NULL) {
+ fprintf(stderr, "can't create thread\n");
+ exit(1);
+ }
+
+ printf("Two client threads are created. Each of them will\n");
+ printf("send data to one of the two ports the server is listening on.\n");
+ printf("The data they send is the port number. Each of them send\n");
+ printf("the data five times, so you should see ten lines below,\n");
+ printf("interleaved in an arbitrary order.\n");
+
+ /* set up the fd array */
+ fds = fds0;
+ other_fds = fds1;
+ fds[0] = listenSock1;
+ fds[1] = listenSock2;
+ nfds = 2;
+ PR_FD_SET(listenSock1, &readFdSet);
+ PR_FD_SET(listenSock2, &readFdSet);
+
+ /* 20 events total */
+ i = 0;
+ while (i < 20) {
+ PRFileDesc **tmp;
+ int nextIndex;
+ int nEvents = 0;
+
+ retVal = PR_Select(0 /* unused */, &readFdSet, NULL, NULL,
+ PR_INTERVAL_NO_TIMEOUT);
+ PR_ASSERT(retVal != 0); /* no timeout */
+ if (retVal == -1) {
+ fprintf(stderr, "PR_Select failed (%d, %d)\n", PR_GetError(),
+ PR_GetOSError());
+ exit(1);
+ }
+
+ nextIndex = 2;
+ /* the two listening sockets */
+ for (j = 0; j < 2; j++) {
+ other_fds[j] = fds[j];
+ if (PR_FD_ISSET(fds[j], &readFdSet)) {
+ PRFileDesc *sock;
+
+ nEvents++;
+ sock = PR_Accept(fds[j], NULL, PR_INTERVAL_NO_TIMEOUT);
+ if (sock == NULL) {
+ fprintf(stderr, "PR_Accept() failed\n");
+ exit(1);
+ }
+ other_fds[nextIndex] = sock;
+ PR_FD_SET(sock, &readFdSet);
+ nextIndex++;
+ }
+ PR_FD_SET(fds[j], &readFdSet);
+ }
+
+ for (j = 2; j < nfds; j++) {
+ if (PR_FD_ISSET(fds[j], &readFdSet)) {
+ PRInt32 nBytes;
+
+ PR_FD_CLR(fds[j], &readFdSet);
+ nEvents++;
+ nBytes = PR_Read(fds[j], buf, sizeof(buf));
+ if (nBytes == -1) {
+ fprintf(stderr, "PR_Read() failed\n");
+ exit(1);
+ }
+ /* Just to be safe */
+ buf[127] = '\0';
+ PR_Close(fds[j]);
+ printf("The server received \"%s\" from a client\n", buf);
+ } else {
+ PR_FD_SET(fds[j], &readFdSet);
+ other_fds[nextIndex] = fds[j];
+ nextIndex++;
+ }
+ }
+
+ PR_ASSERT(retVal == nEvents);
+ /* swap */
+ tmp = fds;
+ fds = other_fds;
+ other_fds = tmp;
+ nfds = nextIndex;
+ i += nEvents;
+ }
+
+ printf("All tests finished\n");
+ PR_Cleanup();
+ return 0;
+}
diff --git a/nsprpub/pr/tests/prttools.h b/nsprpub/pr/tests/prttools.h
new file mode 100644
index 0000000000..e3cac5daa9
--- /dev/null
+++ b/nsprpub/pr/tests/prttools.h
@@ -0,0 +1,11 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* Used in Regress Tool */
+#define NOSTATUS 2
+#define PASS 1
+#define FAIL 0
+
+PRIntn debug_mode=0;
diff --git a/nsprpub/pr/tests/pushtop.c b/nsprpub/pr/tests/pushtop.c
new file mode 100644
index 0000000000..621a7c7248
--- /dev/null
+++ b/nsprpub/pr/tests/pushtop.c
@@ -0,0 +1,73 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* A regression test for bug 794316 */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "prio.h"
+
+static PRIOMethods dummyMethods;
+
+int main()
+{
+ PRDescIdentity topId, middleId, bottomId;
+ PRFileDesc *top, *middle, *bottom;
+ PRFileDesc *fd;
+
+ topId = PR_GetUniqueIdentity("top");
+ middleId = PR_GetUniqueIdentity("middle");
+ bottomId = PR_GetUniqueIdentity("bottom");
+
+ top = PR_CreateIOLayerStub(topId, &dummyMethods);
+ middle = PR_CreateIOLayerStub(middleId, &dummyMethods);
+ bottom = PR_CreateIOLayerStub(bottomId, &dummyMethods);
+
+ fd = bottom;
+ PR_PushIOLayer(fd, PR_TOP_IO_LAYER, middle);
+ PR_PushIOLayer(fd, PR_TOP_IO_LAYER, top);
+
+ top = fd;
+ middle = top->lower;
+ bottom = middle->lower;
+
+ /* Verify that the higher pointers are correct. */
+ if (middle->higher != top) {
+ fprintf(stderr, "middle->higher is wrong\n");
+ fprintf(stderr, "FAILED\n");
+ exit(1);
+ }
+ if (bottom->higher != middle) {
+ fprintf(stderr, "bottom->higher is wrong\n");
+ fprintf(stderr, "FAILED\n");
+ exit(1);
+ }
+
+ top = PR_PopIOLayer(fd, topId);
+ top->dtor(top);
+
+ middle = fd;
+ bottom = middle->lower;
+
+ /* Verify that the higher pointer is correct. */
+ if (bottom->higher != middle) {
+ fprintf(stderr, "bottom->higher is wrong\n");
+ fprintf(stderr, "FAILED\n");
+ exit(1);
+ }
+
+ middle = PR_PopIOLayer(fd, middleId);
+ middle->dtor(middle);
+ if (fd->identity != bottomId) {
+ fprintf(stderr, "The bottom layer has the wrong identity\n");
+ fprintf(stderr, "FAILED\n");
+ exit(1);
+ }
+ fd->dtor(fd);
+
+ printf("PASS\n");
+ return 0;
+}
diff --git a/nsprpub/pr/tests/randseed.c b/nsprpub/pr/tests/randseed.c
new file mode 100644
index 0000000000..2ca14c7af0
--- /dev/null
+++ b/nsprpub/pr/tests/randseed.c
@@ -0,0 +1,137 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+** File: rngseed.c
+** Description:
+** Test NSPR's Random Number Seed generator
+**
+** Initial test: Just make sure it outputs some data.
+**
+** ... more? ... check some iterations to ensure it is random (no dupes)
+** ... more? ... histogram distribution of random numbers
+*/
+
+#include "plgetopt.h"
+#include "nspr.h"
+#include "prrng.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+** Test harness infrastructure
+*/
+PRLogModuleInfo *lm;
+PRLogModuleLevel msgLevel = PR_LOG_NONE;
+PRIntn debug = 0;
+PRUint32 failed_already = 0;
+/* end Test harness infrastructure */
+
+PRIntn optRandCount = 30;
+char buf[40];
+PRSize bufSize = sizeof(buf);
+PRSize rSize;
+PRIntn i;
+
+/*
+** Emit help text for this test
+*/
+static void Help( void )
+{
+ printf("Template: Help(): display your help message(s) here");
+ exit(1);
+} /* end Help() */
+
+static void PrintRand( void *buf, PRIntn size )
+{
+ PRUint32 *rp = buf;
+ PRIntn i;
+
+ printf("%4.4d--\n", size );
+ while (size > 0 ) {
+ switch( size ) {
+ case 1 :
+ printf("%2.2X\n", *(rp++) );
+ size -= 4;
+ break;
+ case 2 :
+ printf("%4.4X\n", *(rp++) );
+ size -= 4;
+ break;
+ case 3 :
+ printf("%6.6X\n", *(rp++) );
+ size -= 4;
+ break;
+ default:
+ while ( size >= 4) {
+ PRIntn i = 3;
+ do {
+ printf("%8.8X ", *(rp++) );
+ size -= 4;
+ } while( i-- );
+ i = 3;
+ printf("\n");
+ }
+ break;
+ } /* end switch() */
+ } /* end while() */
+} /* end PrintRand() */
+
+
+int main(int argc, char **argv)
+{
+ {
+ /*
+ ** Get command line options
+ */
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "hdv");
+
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 'd': /* debug */
+ debug = 1;
+ msgLevel = PR_LOG_ERROR;
+ break;
+ case 'v': /* verbose mode */
+ msgLevel = PR_LOG_DEBUG;
+ break;
+ case 'h': /* help message */
+ Help();
+ break;
+ default:
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+ }
+
+ lm = PR_NewLogModule("Test"); /* Initialize logging */
+ for ( i = 0; i < optRandCount ; i++ ) {
+ memset( buf, 0, bufSize );
+ rSize = PR_GetRandomNoise( buf, bufSize );
+ if (!rSize) {
+ fprintf(stderr, "Not implemented\n" );
+ failed_already = PR_TRUE;
+ break;
+ }
+ if (debug) {
+ PrintRand( buf, rSize );
+ }
+ }
+
+ if (debug) {
+ printf("%s\n", (failed_already)? "FAIL" : "PASS");
+ }
+ return( (failed_already == PR_TRUE )? 1 : 0 );
+} /* main() */
+/* end template.c */
+
diff --git a/nsprpub/pr/tests/ranfile.c b/nsprpub/pr/tests/ranfile.c
new file mode 100644
index 0000000000..a6dcc4ac41
--- /dev/null
+++ b/nsprpub/pr/tests/ranfile.c
@@ -0,0 +1,433 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/***********************************************************************
+**
+** Contact: AOF<freier@netscape.com>
+**
+** Name: ranfile.c
+**
+** Description: Test to hammer on various components of NSPR
+** Modification History:
+** 20-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
+** The debug mode will print all of the printfs associated with this test.
+** The regress mode will be the default mode. Since the regress tool limits
+** the output to a one line status:PASS or FAIL,all of the printf statements
+** have been handled with an if (debug_mode) statement.
+** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to
+** recognize the return code from tha main program.
+***********************************************************************/
+
+
+/***********************************************************************
+** Includes
+***********************************************************************/
+/* Used to get the command line option */
+#include "plgetopt.h"
+
+#include "prinit.h"
+#include "prthread.h"
+#include "prlock.h"
+#include "prcvar.h"
+#include "prmem.h"
+#include "prinrval.h"
+#include "prio.h"
+
+#include <string.h>
+#include <stdio.h>
+
+static PRIntn debug_mode = 0;
+static PRIntn failed_already=0;
+static PRThreadScope thread_scope = PR_LOCAL_THREAD;
+
+typedef enum {sg_go, sg_stop, sg_done} Action;
+typedef enum {sg_okay, sg_open, sg_close, sg_delete, sg_write, sg_seek} Problem;
+
+typedef struct Hammer_s {
+ PRLock *ml;
+ PRCondVar *cv;
+ PRUint32 id;
+ PRUint32 limit;
+ PRUint32 writes;
+ PRThread *thread;
+ PRIntervalTime timein;
+ Action action;
+ Problem problem;
+} Hammer_t;
+
+#define DEFAULT_LIMIT 10
+#define DEFAULT_THREADS 2
+#define DEFAULT_LOOPS 1
+
+static PRInt32 pageSize = 1024;
+static const char* baseName = "./";
+static const char *programName = "Random File";
+
+/***********************************************************************
+** PRIVATE FUNCTION: RandomNum
+** DESCRIPTION:
+** Generate a pseudo-random number
+** INPUTS: None
+** OUTPUTS: None
+** RETURN: A pseudo-random unsigned number, 32-bits wide
+** SIDE EFFECTS:
+** Updates random seed (a static)
+** RESTRICTIONS:
+** None
+** MEMORY: NA
+** ALGORITHM:
+** Uses the current interval timer value, promoted to a 64 bit
+** float as a multiplier for a static residue (which begins
+** as an uninitialized variable). The result is bits [16..48)
+** of the product. Seed is then updated with the return value
+** promoted to a float-64.
+***********************************************************************/
+static PRUint32 RandomNum(void)
+{
+ PRUint32 rv;
+ PRUint64 shift;
+ static PRFloat64 seed = 0x58a9382; /* Just make sure it isn't 0! */
+ PRFloat64 random = seed * (PRFloat64)PR_IntervalNow();
+ LL_USHR(shift, *((PRUint64*)&random), 16);
+ LL_L2UI(rv, shift);
+ seed = (PRFloat64)rv;
+ return rv;
+} /* RandomNum */
+
+/***********************************************************************
+** PRIVATE FUNCTION: Thread
+** DESCRIPTION:
+** Hammer on the file I/O system
+** INPUTS: A pointer to the thread's private data
+** OUTPUTS: None
+** RETURN: None
+** SIDE EFFECTS:
+** Creates, accesses and deletes a file
+** RESTRICTIONS:
+** (Currently) must have file create permission in "/usr/tmp".
+** MEMORY: NA
+** ALGORITHM:
+** This function is a root of a thread
+** 1) Creates a (hopefully) unique file in /usr/tmp/
+** 2) Writes a zero to a random number of sequential pages
+** 3) Closes the file
+** 4) Reopens the file
+** 5) Seeks to a random page within the file
+** 6) Writes a one byte on that page
+** 7) Repeat steps [5..6] for each page in the file
+** 8) Close and delete the file
+** 9) Repeat steps [1..8] until told to stop
+** 10) Notify complete and return
+***********************************************************************/
+static void PR_CALLBACK Thread(void *arg)
+{
+ PRUint32 index;
+ char filename[30];
+ const char zero = 0;
+ PRFileDesc *file = NULL;
+ PRStatus rv = PR_SUCCESS;
+ Hammer_t *cd = (Hammer_t*)arg;
+
+ (void)sprintf(filename, "%ssg%04ld.dat", baseName, cd->id);
+
+ if (debug_mode) {
+ printf("Starting work on %s\n", filename);
+ }
+
+ while (PR_TRUE)
+ {
+ PRUint32 bytes;
+ PRUint32 minor = (RandomNum() % cd->limit) + 1;
+ PRUint32 random = (RandomNum() % cd->limit) + 1;
+ PRUint32 pages = (RandomNum() % cd->limit) + 10;
+ while (minor-- > 0)
+ {
+ cd->problem = sg_okay;
+ if (cd->action != sg_go) {
+ goto finished;
+ }
+ cd->problem = sg_open;
+ file = PR_Open(filename, PR_RDWR|PR_CREATE_FILE, 0666);
+ if (file == NULL) {
+ goto finished;
+ }
+ for (index = 0; index < pages; index++)
+ {
+ cd->problem = sg_okay;
+ if (cd->action != sg_go) {
+ goto close;
+ }
+ cd->problem = sg_seek;
+ bytes = PR_Seek(file, pageSize * index, PR_SEEK_SET);
+ if (bytes != pageSize * index) {
+ goto close;
+ }
+ cd->problem = sg_write;
+ bytes = PR_Write(file, &zero, sizeof(zero));
+ if (bytes <= 0) {
+ goto close;
+ }
+ cd->writes += 1;
+ }
+ cd->problem = sg_close;
+ rv = PR_Close(file);
+ if (rv != PR_SUCCESS) {
+ goto purge;
+ }
+
+ cd->problem = sg_okay;
+ if (cd->action != sg_go) {
+ goto purge;
+ }
+
+ cd->problem = sg_open;
+ file = PR_Open(filename, PR_RDWR, 0666);
+ for (index = 0; index < pages; index++)
+ {
+ cd->problem = sg_okay;
+ if (cd->action != sg_go) {
+ goto close;
+ }
+ cd->problem = sg_seek;
+ bytes = PR_Seek(file, pageSize * index, PR_SEEK_SET);
+ if (bytes != pageSize * index) {
+ goto close;
+ }
+ cd->problem = sg_write;
+ bytes = PR_Write(file, &zero, sizeof(zero));
+ if (bytes <= 0) {
+ goto close;
+ }
+ cd->writes += 1;
+ random = (random + 511) % pages;
+ }
+ cd->problem = sg_close;
+ rv = PR_Close(file);
+ if (rv != PR_SUCCESS) {
+ goto purge;
+ }
+ cd->problem = sg_delete;
+ rv = PR_Delete(filename);
+ if (rv != PR_SUCCESS) {
+ goto finished;
+ }
+ }
+ }
+
+close:
+ (void)PR_Close(file);
+purge:
+ (void)PR_Delete(filename);
+finished:
+ PR_Lock(cd->ml);
+ cd->action = sg_done;
+ PR_NotifyCondVar(cd->cv);
+ PR_Unlock(cd->ml);
+
+ if (debug_mode) {
+ printf("Ending work on %s\n", filename);
+ }
+
+ return;
+} /* Thread */
+
+static Hammer_t hammer[100];
+static PRCondVar *cv;
+/***********************************************************************
+** PRIVATE FUNCTION: main
+** DESCRIPTION:
+** Hammer on the file I/O system
+** INPUTS: The usual argc and argv
+** argv[0] - program name (not used)
+** argv[1] - the number of times to execute the major loop
+** argv[2] - the number of threads to toss into the batch
+** argv[3] - the clipping number applied to randoms
+** default values: loops = 2, threads = 10, limit = 57
+** OUTPUTS: None
+** RETURN: None
+** SIDE EFFECTS:
+** Creates, accesses and deletes lots of files
+** RESTRICTIONS:
+** (Currently) must have file create permission in "/usr/tmp".
+** MEMORY: NA
+** ALGORITHM:
+** 1) Fork a "Thread()"
+** 2) Wait for 'interleave' seconds
+** 3) For [0..'threads') repeat [1..2]
+** 4) Mark all objects to stop
+** 5) Collect the threads, accumulating the results
+** 6) For [0..'loops') repeat [1..5]
+** 7) Print accumulated results and exit
+**
+** Characteristic output (from IRIX)
+** Random File: Using loops = 2, threads = 10, limit = 57
+** Random File: [min [avg] max] writes/sec average
+***********************************************************************/
+int main(int argc, char **argv)
+{
+ PRLock *ml;
+ PRUint32 id = 0;
+ int active, poll;
+ PRIntervalTime interleave;
+ PRIntervalTime duration = 0;
+ int limit = 0, loops = 0, threads = 0, times;
+ PRUint32 writes, writesMin = 0x7fffffff, writesTot = 0, durationTot = 0, writesMax = 0;
+
+ const char *where[] = {"okay", "open", "close", "delete", "write", "seek"};
+
+ /* The command line argument: -d is used to determine if the test is being run
+ in debug mode. The regress tool requires only one line output:PASS or FAIL.
+ All of the printfs associated with this test has been handled with a if (debug_mode)
+ test.
+ Usage: test_name -d
+ */
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "Gdl:t:i:");
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 'G': /* global threads */
+ thread_scope = PR_GLOBAL_THREAD;
+ break;
+ case 'd': /* debug mode */
+ debug_mode = 1;
+ break;
+ case 'l': /* limiting number */
+ limit = atoi(opt->value);
+ break;
+ case 't': /* number of threads */
+ threads = atoi(opt->value);
+ break;
+ case 'i': /* iteration counter */
+ loops = atoi(opt->value);
+ break;
+ default:
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ /* main test */
+
+ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
+ PR_STDIO_INIT();
+
+ interleave = PR_SecondsToInterval(10);
+
+ ml = PR_NewLock();
+ cv = PR_NewCondVar(ml);
+
+ if (loops == 0) {
+ loops = DEFAULT_LOOPS;
+ }
+ if (limit == 0) {
+ limit = DEFAULT_LIMIT;
+ }
+ if (threads == 0) {
+ threads = DEFAULT_THREADS;
+ }
+
+ if (debug_mode) printf(
+ "%s: Using loops = %d, threads = %d, limit = %d and %s threads\n",
+ programName, loops, threads, limit,
+ (thread_scope == PR_LOCAL_THREAD) ? "LOCAL" : "GLOBAL");
+
+ for (times = 0; times < loops; ++times)
+ {
+ if (debug_mode) {
+ printf("%s: Setting concurrency level to %d\n", programName, times + 1);
+ }
+ PR_SetConcurrency(times + 1);
+ for (active = 0; active < threads; active++)
+ {
+ hammer[active].ml = ml;
+ hammer[active].cv = cv;
+ hammer[active].id = id++;
+ hammer[active].writes = 0;
+ hammer[active].action = sg_go;
+ hammer[active].problem = sg_okay;
+ hammer[active].limit = (RandomNum() % limit) + 1;
+ hammer[active].timein = PR_IntervalNow();
+ hammer[active].thread = PR_CreateThread(
+ PR_USER_THREAD, Thread, &hammer[active],
+ PR_GetThreadPriority(PR_GetCurrentThread()),
+ thread_scope, PR_JOINABLE_THREAD, 0);
+
+ PR_Lock(ml);
+ PR_WaitCondVar(cv, interleave); /* start new ones slowly */
+ PR_Unlock(ml);
+ }
+
+ /*
+ * The last thread started has had the opportunity to run for
+ * 'interleave' seconds. Now gather them all back in.
+ */
+ PR_Lock(ml);
+ for (poll = 0; poll < threads; poll++)
+ {
+ if (hammer[poll].action == sg_go) { /* don't overwrite done */
+ hammer[poll].action = sg_stop; /* ask him to stop */
+ }
+ }
+ PR_Unlock(ml);
+
+ while (active > 0)
+ {
+ for (poll = 0; poll < threads; poll++)
+ {
+ PR_Lock(ml);
+ while (hammer[poll].action < sg_done) {
+ PR_WaitCondVar(cv, PR_INTERVAL_NO_TIMEOUT);
+ }
+ PR_Unlock(ml);
+
+ active -= 1; /* this is another one down */
+ (void)PR_JoinThread(hammer[poll].thread);
+ hammer[poll].thread = NULL;
+ if (hammer[poll].problem == sg_okay)
+ {
+ duration = PR_IntervalToMilliseconds(
+ PR_IntervalNow() - hammer[poll].timein);
+ writes = hammer[poll].writes * 1000 / duration;
+ if (writes < writesMin) {
+ writesMin = writes;
+ }
+ if (writes > writesMax) {
+ writesMax = writes;
+ }
+ writesTot += hammer[poll].writes;
+ durationTot += duration;
+ }
+ else if (debug_mode) printf(
+ "%s: test failed %s after %ld seconds\n",
+ programName, where[hammer[poll].problem], duration);
+ else {
+ failed_already=1;
+ }
+ }
+ }
+ }
+ if (debug_mode) printf(
+ "%s: [%ld [%ld] %ld] writes/sec average\n",
+ programName, writesMin, writesTot * 1000 / durationTot, writesMax);
+
+ PR_DestroyCondVar(cv);
+ PR_DestroyLock(ml);
+
+ if (failed_already)
+ {
+ printf("FAIL\n");
+ return 1;
+ }
+ else
+ {
+ printf("PASS\n");
+ return 0;
+ }
+} /* main */
diff --git a/nsprpub/pr/tests/reinit.c b/nsprpub/pr/tests/reinit.c
new file mode 100644
index 0000000000..b4dfa4d9b9
--- /dev/null
+++ b/nsprpub/pr/tests/reinit.c
@@ -0,0 +1,35 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* This test verifies that NSPR can be cleaned up and reinitialized. */
+
+#include "nspr.h"
+#include <stdio.h>
+
+int main()
+{
+ PRStatus rv;
+
+ fprintf(stderr, "Init 1\n");
+ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
+ fprintf(stderr, "Cleanup 1\n");
+ rv = PR_Cleanup();
+ if (rv != PR_SUCCESS) {
+ fprintf(stderr, "FAIL\n");
+ return 1;
+ }
+
+ fprintf(stderr, "Init 2\n");
+ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
+ fprintf(stderr, "Cleanup 2\n");
+ rv = PR_Cleanup();
+ if (rv != PR_SUCCESS) {
+ fprintf(stderr, "FAIL\n");
+ return 1;
+ }
+
+ fprintf(stderr, "PASS\n");
+ return 0;
+}
diff --git a/nsprpub/pr/tests/rmdir.c b/nsprpub/pr/tests/rmdir.c
new file mode 100644
index 0000000000..c1400d7287
--- /dev/null
+++ b/nsprpub/pr/tests/rmdir.c
@@ -0,0 +1,99 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+** File: rmdir.c
+** Description: Demonstrate bugzilla 80884.
+**
+** after fix to unix_errors.c, message should report correct
+** failure of PR_Rmdir().
+**
+**
+**
+*/
+
+#include <prio.h>
+#include <stdio.h>
+#include <prerror.h>
+#include <prlog.h>
+#include "plgetopt.h"
+
+#define DIRNAME "xxxBug80884/"
+#define FILENAME "file80883"
+
+PRBool failed_already = PR_FALSE;
+PRBool debug_mode = PR_FALSE;
+
+PRLogModuleInfo *lm;
+
+/*
+** Help() -- print Usage information
+*/
+static void Help( void ) {
+ fprintf(stderr, "template usage:\n"
+ "\t-d debug mode\n"
+ );
+} /* --- end Help() */
+
+int main(int argc, char **argv)
+{
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "dh");
+ PRFileDesc* fd;
+ PRErrorCode err;
+
+ /* parse command line options */
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option) {
+ case 'd': /* debug mode */
+ debug_mode = PR_TRUE;
+ break;
+ case 'h':
+ default:
+ Help();
+ return 2;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ lm = PR_NewLogModule( "testcase" );
+
+ (void) PR_MkDir( DIRNAME, 0777);
+ fd = PR_Open( DIRNAME FILENAME, PR_CREATE_FILE|PR_RDWR, 0666);
+ if (fd == 0) {
+ PRErrorCode err = PR_GetError();
+ fprintf(stderr, "create file fails: %d: %s\n", err,
+ PR_ErrorToString(err, PR_LANGUAGE_I_DEFAULT));
+ failed_already = PR_TRUE;
+ goto Finished;
+ }
+
+ PR_Close(fd);
+
+ if (PR_RmDir( DIRNAME ) == PR_SUCCESS) {
+ fprintf(stderr, "remove directory succeeds\n");
+ failed_already = PR_TRUE;
+ goto Finished;
+ }
+
+ err = PR_GetError();
+ fprintf(stderr, "remove directory fails with: %d: %s\n", err,
+ PR_ErrorToString(err, PR_LANGUAGE_I_DEFAULT));
+
+ (void) PR_Delete( DIRNAME FILENAME);
+ (void) PR_RmDir( DIRNAME );
+
+ return 0;
+
+Finished:
+ if ( debug_mode ) {
+ printf("%s\n", ( failed_already ) ? "FAILED" : "PASS" );
+ }
+ return( (failed_already)? 1 : 0 );
+} /* --- end main() */
+/* --- end template.c */
diff --git a/nsprpub/pr/tests/runtests.pl b/nsprpub/pr/tests/runtests.pl
new file mode 100755
index 0000000000..326c08f862
--- /dev/null
+++ b/nsprpub/pr/tests/runtests.pl
@@ -0,0 +1,371 @@
+#!/usr/bin/perl
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+use POSIX qw(:sys_wait_h);
+use POSIX qw(setsid);
+use FileHandle;
+
+# Constants
+$WINOS = "MSWin32";
+
+$osname = $^O;
+
+use Cwd;
+if ($osname =~ $WINOS) {
+ # Windows
+ require Win32::Process;
+ require Win32;
+}
+
+# Get environment variables.
+$output_file = $ENV{NSPR_TEST_LOGFILE};
+$timeout = $ENV{TEST_TIMEOUT};
+
+$timeout = 0 if (!defined($timeout));
+
+sub getTime {
+ ($second, $minute, $hour, $dayOfMonth, $month, $yearOffset, $dayOfWeek, $dayOfYear, $daylightSavings) = localtime();
+
+ $year = 1900 + $yearOffset;
+
+ $theTime = sprintf("%04d-%02d-%02d %02d:%02d:%02d",$year,$month,$dayOfMonth,$hour,$minute,$second);
+ return $theTime;
+}
+
+sub open_log {
+
+ if (!defined($output_file)) {
+ print "No output file.\n";
+ # null device
+ if ($osname =~ $WINOS) {
+ $output_file = "nul";
+ } else {
+ $output_file = "/dev/null";
+ }
+ }
+
+ # use STDOUT for OF (to print summary of test results)
+ open(OF, ">&STDOUT") or die "Can't reuse STDOUT for OF\n";
+ OF->autoflush;
+ # reassign STDOUT to $output_file (to print details of test results)
+ open(STDOUT, ">$output_file") or die "Can't open file $output_file for STDOUT\n";
+ STDOUT->autoflush;
+ # redirect STDERR to STDOUT
+ open(STDERR, ">&STDOUT") or die "Can't redirect STDERR to STDOUT\n";
+ STDERR->autoflush;
+
+ # Print header test in summary
+ $now = getTime;
+ print OF "\nNSPR Test Results - tests\n";
+ print OF "\nBEGIN\t\t\t$now\n";
+ print OF "NSPR_TEST_LOGFILE\t$output_file\n";
+ print OF "TEST_TIMEOUT\t$timeout\n\n";
+ print OF "\nTest\t\t\tResult\n\n";
+}
+
+sub close_log {
+ # end of test marker in summary
+ $now = getTime;
+ print OF "END\t\t\t$now\n";
+
+ close(OF) or die "Can't close file OF\n";
+ close(STDERR) or die "Can't close STDERR\n";
+ close(STDOUT) or die "Can't close STDOUT\n";
+}
+
+sub print_begin {
+$lprog = shift;
+
+ # Summary output
+ print OF "$prog";
+ # Full output
+ $now = getTime;
+ print "BEGIN TEST: $lprog ($now)\n\n";
+}
+
+sub print_end {
+($lprog, $exit_status, $exit_signal, $exit_core) = @_;
+
+ if (($exit_status == 0) && ($exit_signal == 0) && ($exit_core == 0)) {
+ $str_status = "Passed";
+ } else {
+ $str_status = "FAILED";
+ }
+ if ($exit_signal != 0) {
+ $str_signal = " - signal $exit_signal";
+ } else {
+ $str_signal = "";
+ }
+ if ($exit_core != 0) {
+ $str_core = " - core dumped";
+ } else {
+ $str_core = "";
+ }
+ $now = getTime;
+ # Full output
+ print "\nEND TEST: $lprog ($now)\n";
+ print "TEST STATUS: $lprog = $str_status (exit status " . $exit_status . $str_signal . $str_core . ")\n";
+ print "--------------------------------------------------\n\n";
+ # Summary output
+ print OF "\t\t\t$str_status\n";
+}
+
+sub ux_start_prog {
+# parameters:
+$lprog = shift; # command to run
+
+ # Create a process group for the child
+ # so we can kill all of it if needed
+ setsid or die "setsid failed: $!";
+ # Start test program
+ exec("./$lprog");
+ # We should not be here unless exec failed.
+ print "Faild to exec $lprog";
+ exit 1 << 8;
+}
+
+sub ux_wait_timeout {
+# parameters:
+$lpid = shift; # child process id
+$ltimeout = shift; # timeout
+
+ if ($ltimeout == 0) {
+ # No timeout: use blocking wait
+ $ret = waitpid($lpid,0);
+ # Exit and don't kill
+ $lstatus = $?;
+ $ltimeout = -1;
+ } else {
+ while ($ltimeout > 0) {
+ # Check status of child using non blocking wait
+ $ret = waitpid($lpid, WNOHANG);
+ if ($ret == 0) {
+ # Child still running
+ # print "Time left=$ltimeout\n";
+ sleep 1;
+ $ltimeout--;
+ } else {
+ # Child has ended
+ $lstatus = $?;
+ # Exit the wait loop and don't kill
+ $ltimeout = -1;
+ }
+ }
+ }
+
+ if ($ltimeout == 0) {
+ # we ran all the timeout: it's time to kill the child
+ print "Timeout ! Kill child process $lpid\n";
+ # Kill the child process and group
+ kill(-9,$lpid);
+ $lstatus = 9;
+ }
+
+ return $lstatus;
+}
+
+sub ux_test_prog {
+# parameters:
+$prog = shift; # Program to test
+
+ $child_pid = fork;
+ if ($child_pid == 0) {
+ # we are in the child process
+ print_begin($prog);
+ ux_start_prog($prog);
+ } else {
+ # we are in the parent process
+ $status = ux_wait_timeout($child_pid,$timeout);
+ # See Perlvar for documentation of $?
+ # exit status = $status >> 8
+ # exit signal = $status & 127 (no signal = 0)
+ # core dump = $status & 128 (no core = 0)
+ print_end($prog, $status >> 8, $status & 127, $status & 128);
+ }
+
+ return $status;
+}
+
+sub win_path {
+$lpath = shift;
+
+ # MSYS drive letter = /c/ -> c:/
+ $lpath =~ s/^\/(\w)\//$1:\//;
+ # Cygwin drive letter = /cygdrive/c/ -> c:/
+ $lpath =~ s/^\/cygdrive\/(\w)\//$1:\//;
+ # replace / with \\
+ $lpath =~ s/\//\\\\/g;
+
+ return $lpath;
+}
+
+sub win_ErrorReport{
+ print Win32::FormatMessage( Win32::GetLastError() );
+}
+
+sub win_test_prog {
+# parameters:
+$prog = shift; # Program to test
+
+ $status = 1;
+ $curdir = getcwd;
+ $curdir = win_path($curdir);
+ $prog_path = "$curdir\\$prog.exe";
+
+ print_begin($prog);
+
+ Win32::Process::Create($ProcessObj,
+ "$prog_path",
+ "$prog",
+ 0,
+ NORMAL_PRIORITY_CLASS,
+ ".")|| die win_ErrorReport();
+ $retwait = $ProcessObj->Wait($timeout * 1000);
+
+ if ( $retwait == 0) {
+ # the prog didn't finish after the timeout: kill
+ $ProcessObj->Kill($status);
+ print "Timeout ! Process killed with exit status $status\n";
+ } else {
+ # the prog finished before the timeout: get exit status
+ $ProcessObj->GetExitCode($status);
+ }
+ # There is no signal, no core on Windows
+ print_end($prog, $status, 0, 0);
+
+ return $status
+}
+
+# MAIN ---------------
+@progs = (
+"abstract",
+"accept",
+"acceptread",
+"acceptreademu",
+"affinity",
+"alarm",
+"anonfm",
+"atomic",
+"attach",
+"bigfile",
+"cleanup",
+"cltsrv",
+"concur",
+"cvar",
+"cvar2",
+"dlltest",
+"dtoa",
+"errcodes",
+"exit",
+"fdcach",
+"fileio",
+"foreign",
+"formattm",
+"fsync",
+"gethost",
+"getproto",
+"i2l",
+"initclk",
+"inrval",
+"instrumt",
+"intrio",
+"intrupt",
+"io_timeout",
+"ioconthr",
+"join",
+"joinkk",
+"joinku",
+"joinuk",
+"joinuu",
+"layer",
+"lazyinit",
+"libfilename",
+"lltest",
+"lock",
+"lockfile",
+"logfile",
+"logger",
+"many_cv",
+"nameshm1",
+"nblayer",
+"nonblock",
+"ntioto",
+"ntoh",
+"op_2long",
+"op_excl",
+"op_filnf",
+"op_filok",
+"op_nofil",
+"parent",
+"parsetm",
+"peek",
+"perf",
+"pipeping",
+"pipeping2",
+"pipeself",
+"poll_nm",
+"poll_to",
+"pollable",
+"prftest",
+"prfz",
+"primblok",
+"provider",
+"prpollml",
+"pushtop",
+"ranfile",
+"randseed",
+"reinit",
+"rwlocktest",
+"sel_spd",
+"selct_er",
+"selct_nm",
+"selct_to",
+"selintr",
+"sema",
+"semaerr",
+"semaping",
+"sendzlf",
+"server_test",
+"servr_kk",
+"servr_uk",
+"servr_ku",
+"servr_uu",
+"short_thread",
+"sigpipe",
+"socket",
+"sockopt",
+"sockping",
+"sprintf",
+"stack",
+"stdio",
+"str2addr",
+"strod",
+"switch",
+"system",
+"testbit",
+"testfile",
+"threads",
+"timemac",
+"timetest",
+"tpd",
+"udpsrv",
+"vercheck",
+"version",
+"writev",
+"xnotify",
+"zerolen");
+
+open_log;
+
+foreach $current_prog (@progs) {
+ if ($osname =~ $WINOS) {
+ win_test_prog($current_prog);
+ } else {
+ ux_test_prog($current_prog);
+ }
+}
+
+close_log;
diff --git a/nsprpub/pr/tests/runtests.sh b/nsprpub/pr/tests/runtests.sh
new file mode 100755
index 0000000000..8d3144019d
--- /dev/null
+++ b/nsprpub/pr/tests/runtests.sh
@@ -0,0 +1,277 @@
+#!/bin/sh
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+if test -z $1
+then
+ echo "usage: $0 <path-to-dist>"
+ exit 1
+fi
+
+cd $1/lib
+ABS_LIB=$PWD
+cd -
+
+export DYLD_LIBRARY_PATH=${ABS_LIB}:${DYLD_LIBRARY_PATH}
+export LD_LIBRARY_PATH=${ABS_LIB}:${LD_LIBRARY_PATH}
+export PATH=${ABS_LIB}:${PATH}
+
+#
+# runtests.sh
+# Bourne shell script for nspr tests
+#
+
+SYSTEM_INFO=`uname -a`
+OS_ARCH=`uname -s`
+
+if [ $OS_ARCH = "Windows_NT" ] || [ $OS_ARCH = "OS/2" ]
+then
+ NULL_DEVICE=nul
+else
+ NULL_DEVICE=/dev/null
+ FILE_D=`ulimit -n`
+ if [ $FILE_D -lt 512 ]
+ then
+ ulimit -n 512
+ fi
+fi
+
+#
+# Irrevelant tests
+#
+#bug1test - used to demonstrate a bug on NT
+#bigfile2 - requires 4Gig file creation. See BugZilla #5451
+#bigfile3 - requires 4Gig file creation. See BugZilla #5451
+#dbmalloc - obsolete; originally for testing debug version of nspr's malloc
+#dbmalloc1 - obsolete; originally for testing debug version of nspr's malloc
+#depend - obsolete; used to test a initial spec for library dependencies
+#dceemu - used to tests special functions in NSPR for DCE emulation
+#ipv6 - IPV6 not in use by NSPR clients
+#mbcs - tests use of multi-byte charset for filenames. See BugZilla #25140
+#io_timeoutk - obsolete; subsumed in io_timeout
+#io_timeoutu - obsolete; subsumed in io_timeout
+#prftest1 - obsolete; subsumed by prftest
+#prftest2 - obsolete; subsumed by prftest
+#prselect - obsolete; PR_Select is obsolete
+#select2 - obsolete; PR_Select is obsolete
+#sem - obsolete; PRSemaphore is obsolete
+#stat - for OS2?
+#suspend - private interfaces PR_SuspendAll, PR_ResumeAll, etc..
+#thruput - needs to be run manually as client/server
+#time - used to measure time with native calls and nspr calls
+#tmoacc - should be run with tmocon
+#tmocon - should be run with tmoacc
+#op_noacc - limited use
+#yield - limited use for PR_Yield
+
+#
+# Tests not run (but should)
+#
+
+#forktest (failed on IRIX)
+#multiwait - fails on Linux 64bit since NSPR v 4.4 from 2004.
+#nbconn - fails on some platforms
+#poll_er - fails on some platforms? limited use?
+#prpoll - the bad-FD test needs to be moved to a different test
+#sleep - specific to OS/2
+#
+# all of the following were disabled in 2019 when reenabling CI tests,
+# because they failed on at least one of the platforms:
+#
+# cltsrv
+# cvar
+# gethost
+# getproto
+# layer
+# logfile
+# nameshm1
+# nblayer
+# nonblock
+# ntioto
+# op_2long
+# parent
+# provider
+# ranfile
+# socket
+# sockopt
+# vercheck
+
+#LOGFILE=${NSPR_TEST_LOGFILE:-$NULL_DEVICE}
+LOGFILE=nspr-test.log
+
+#
+# Tests run on all platforms
+#
+
+TESTS="
+abstract
+accept
+acceptread
+acceptreademu
+affinity
+alarm
+anonfm
+atomic
+attach
+bigfile
+cleanup
+concur
+cvar2
+dlltest
+dtoa
+errcodes
+exit
+fdcach
+fileio
+foreign
+formattm
+fsync
+i2l
+initclk
+inrval
+instrumt
+intrio
+intrupt
+io_timeout
+ioconthr
+join
+joinkk
+joinku
+joinuk
+joinuu
+lazyinit
+libfilename
+lltest
+lock
+lockfile
+logger
+many_cv
+ntoh
+op_excl
+op_filnf
+op_filok
+op_nofil
+parsetm
+peek
+perf
+pipeping
+pipeping2
+pipeself
+poll_nm
+poll_to
+pollable
+prftest
+prfz
+primblok
+prpollml
+pushtop
+randseed
+reinit
+rwlocktest
+sel_spd
+selct_er
+selct_nm
+selct_to
+selintr
+sema
+semaerr
+semaping
+sendzlf
+server_test
+servr_kk
+servr_uk
+servr_ku
+servr_uu
+short_thread
+sigpipe
+sockping
+sprintf
+stack
+stdio
+str2addr
+strod
+switch
+system
+testbit
+testfile
+threads
+timemac
+timetest
+tpd
+udpsrv
+version
+writev
+xnotify
+zerolen"
+
+rval=0
+
+
+#
+# When set, value of the environment variable TEST_TIMEOUT is the maximum
+# time (secs) allowed for a test program beyond which it is terminated.
+# If TEST_TIMEOUT is not set or if it's value is 0, then test programs
+# don't timeout.
+#
+# Running runtests.ksh under MKS toolkit on NT, 95, 98 does not cause
+# timeout detection correctly. For these platforms, do not attempt timeout
+# test. (lth).
+#
+#
+
+OS_PLATFORM=`uname`
+OBJDIR=`basename $PWD`
+printf "\nNSPR Test Results - $OBJDIR\n\n"
+printf "BEGIN\t\t\t`date`\n"
+printf "NSPR_TEST_LOGFILE\t${LOGFILE}\n\n"
+printf "Test\t\t\tResult\n\n"
+if [ $OS_PLATFORM = "Windows_95" ] || [ $OS_PLATFORM = "Windows_98" ] || [ $OS_PLATFORM = "Windows_NT" ] || [ $OS_PLATFORM = "OS/2" ] ; then
+ for prog in $TESTS
+ do
+ printf "$prog (`date +%T`)"
+ printf "\nBEGIN TEST: $prog\n\n" >> ${LOGFILE} 2>&1
+ ./$prog >> ${LOGFILE} 2>&1
+ if [ 0 = $? ] ; then
+ printf "\t\t\tPassed\n";
+ else
+ printf "\t\t\tFAILED\n";
+ rval=1
+ fi;
+ printf "\nEND TEST: $prog\n\n" >> ${LOGFILE} 2>&1
+ done
+else
+ for prog in $TESTS
+ do
+ printf "$prog (`date +%T`)"
+ printf "\nBEGIN TEST: $prog\n\n" >> ${LOGFILE} 2>&1
+ export test_rval
+ ./$prog >> ${LOGFILE} 2>&1 &
+ test_pid=$!
+ sleep_pid=0
+ if test -n "$TEST_TIMEOUT" && test "$TEST_TIMEOUT" -gt 0
+ then
+ (sleep $TEST_TIMEOUT; kill $test_pid >/dev/null 2>&1 ) &
+ sleep_pid=$!
+ fi
+ wait $test_pid
+ test_rval=$?
+ [ $sleep_pid -eq 0 ] || kill $sleep_pid >/dev/null 2>&1
+ if [ 0 = $test_rval ] ; then
+ printf "\t\t\tPassed\n";
+ else
+ printf "\t\t\tFAILED\n";
+ rval=1
+ fi;
+ printf "\nEND TEST: $prog\n\n" >> ${LOGFILE} 2>&1
+ done
+fi;
+
+if [ $rval -ne 0 ]; then
+ cat ${LOGFILE}
+fi
+
+printf "END\t\t\t`date`\n"
+exit $rval
+
diff --git a/nsprpub/pr/tests/runy2ktests.ksh b/nsprpub/pr/tests/runy2ktests.ksh
new file mode 100644
index 0000000000..56f7d3c5e3
--- /dev/null
+++ b/nsprpub/pr/tests/runy2ktests.ksh
@@ -0,0 +1,237 @@
+#!/bin/ksh
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#
+# 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" ] || [ $OS_ARCH = "Windows_95" ]
+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"`
+ ;;
+ Windows_95)
+ 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"`
+ ;;
+ Windows_95)
+ 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
+ ;;
+ Windows_95)
+ 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/nsprpub/pr/tests/rwlockrank.c b/nsprpub/pr/tests/rwlockrank.c
new file mode 100644
index 0000000000..d77eb9680a
--- /dev/null
+++ b/nsprpub/pr/tests/rwlockrank.c
@@ -0,0 +1,122 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * RWLock rank tests
+ */
+
+#include "nspr.h"
+#include "plgetopt.h"
+
+static int _debug_on;
+static PRRWLock *rwlock0;
+static PRRWLock *rwlock1;
+static PRRWLock *rwlock2;
+
+static void rwtest(void *args)
+{
+ PR_RWLock_Rlock(rwlock1);
+ PR_RWLock_Unlock(rwlock1);
+
+ PR_RWLock_Rlock(rwlock1);
+ PR_RWLock_Unlock(rwlock1);
+
+ /* Test correct lock rank. */
+ PR_RWLock_Rlock(rwlock1);
+ PR_RWLock_Rlock(rwlock2);
+ PR_RWLock_Unlock(rwlock2);
+ PR_RWLock_Unlock(rwlock1);
+
+ PR_RWLock_Rlock(rwlock1);
+ PR_RWLock_Rlock(rwlock2);
+ PR_RWLock_Unlock(rwlock1);
+ PR_RWLock_Unlock(rwlock2);
+
+ PR_RWLock_Rlock(rwlock1);
+ PR_RWLock_Rlock(rwlock0);
+ PR_RWLock_Rlock(rwlock2);
+ PR_RWLock_Unlock(rwlock2);
+ PR_RWLock_Unlock(rwlock0);
+ PR_RWLock_Unlock(rwlock1);
+
+#if 0
+ /* Test incorrect lock rank. */
+ PR_RWLock_Rlock(rwlock2);
+ PR_RWLock_Rlock(rwlock1);
+ PR_RWLock_Unlock(rwlock1);
+ PR_RWLock_Unlock(rwlock2);
+
+ PR_RWLock_Rlock(rwlock2);
+ PR_RWLock_Rlock(rwlock0);
+ PR_RWLock_Rlock(rwlock1);
+ PR_RWLock_Unlock(rwlock1);
+ PR_RWLock_Unlock(rwlock0);
+ PR_RWLock_Unlock(rwlock2);
+#endif
+}
+
+int main(int argc, char **argv)
+{
+ PRStatus rc;
+ PRThread *thread;
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "d");
+
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option) {
+ case 'd': /* debug mode */
+ _debug_on = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ rwlock0 = PR_NewRWLock(PR_RWLOCK_RANK_NONE, "Lock 0");
+ if (rwlock0 == NULL) {
+ fprintf(stderr, "PR_NewRWLock failed - error %d\n",
+ (int)PR_GetError());
+ return 1;
+ }
+ rwlock1 = PR_NewRWLock(1, "Lock 1");
+ if (rwlock1 == NULL) {
+ fprintf(stderr, "PR_NewRWLock failed - error %d\n",
+ (int)PR_GetError());
+ return 1;
+ }
+ rwlock2 = PR_NewRWLock(2, "Lock 2");
+ if (rwlock2 == NULL) {
+ fprintf(stderr, "PR_NewRWLock failed - error %d\n",
+ (int)PR_GetError());
+ return 1;
+ }
+
+ thread = PR_CreateThread(PR_USER_THREAD, rwtest, NULL, PR_PRIORITY_NORMAL,
+ PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0);
+ if (thread == NULL) {
+ fprintf(stderr, "PR_CreateThread failed - error %d\n",
+ (int)PR_GetError());
+ PR_ProcessExit(2);
+ }
+ if (_debug_on) {
+ printf("%s: created thread = %p\n", argv[0], thread);
+ }
+
+ rc = PR_JoinThread(thread);
+ PR_ASSERT(rc == PR_SUCCESS);
+
+ PR_DestroyRWLock(rwlock0);
+ rwlock0 = NULL;
+ PR_DestroyRWLock(rwlock1);
+ rwlock1 = NULL;
+ PR_DestroyRWLock(rwlock2);
+ rwlock2 = NULL;
+
+ printf("PASS\n");
+ return 0;
+}
diff --git a/nsprpub/pr/tests/rwlocktest.c b/nsprpub/pr/tests/rwlocktest.c
new file mode 100644
index 0000000000..396103c341
--- /dev/null
+++ b/nsprpub/pr/tests/rwlocktest.c
@@ -0,0 +1,213 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+
+/*
+ *
+ * RWLock tests
+ *
+ * Several threads are created to access and modify data arrays using
+ * PRRWLocks for synchronization. Two data arrays, array_A and array_B, are
+ * initialized with random data and a third array, array_C, is initialized
+ * with the sum of the first 2 arrays.
+ *
+ * Each one of the threads acquires a read lock to verify that the sum of
+ * the arrays A and B is equal to array C, and acquires a write lock to
+ * consistently update arrays A and B so that their is equal to array C.
+ *
+ */
+
+#include "nspr.h"
+#include "plgetopt.h"
+#include "prrwlock.h"
+
+static int _debug_on;
+static void rwtest(void *args);
+static PRInt32 *array_A,*array_B,*array_C;
+static void update_array(void);
+static void check_array(void);
+
+typedef struct thread_args {
+ PRRWLock *rwlock;
+ PRInt32 loop_cnt;
+} thread_args;
+
+PRFileDesc *output;
+PRFileDesc *errhandle;
+
+#define DEFAULT_THREAD_CNT 4
+#define DEFAULT_LOOP_CNT 100
+#define TEST_ARRAY_SIZE 100
+
+int main(int argc, char **argv)
+{
+ PRInt32 cnt;
+ PRStatus rc;
+ PRInt32 i;
+
+ PRInt32 thread_cnt = DEFAULT_THREAD_CNT;
+ PRInt32 loop_cnt = DEFAULT_LOOP_CNT;
+ PRThread **threads;
+ thread_args *params;
+ PRRWLock *rwlock1;
+
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "dt:c:");
+
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 'd': /* debug mode */
+ _debug_on = 1;
+ break;
+ case 't': /* thread count */
+ thread_cnt = atoi(opt->value);
+ break;
+ case 'c': /* loop count */
+ loop_cnt = atoi(opt->value);
+ break;
+ default:
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ PR_SetConcurrency(4);
+
+ output = PR_GetSpecialFD(PR_StandardOutput);
+ errhandle = PR_GetSpecialFD(PR_StandardError);
+
+ rwlock1 = PR_NewRWLock(0,"Lock 1");
+ if (rwlock1 == NULL) {
+ PR_fprintf(errhandle, "PR_NewRWLock failed - error %d\n",
+ PR_GetError());
+ return 1;
+ }
+
+ threads = (PRThread**) PR_CALLOC(sizeof(PRThread*) * thread_cnt);
+ params = (thread_args *) PR_CALLOC(sizeof(thread_args) * thread_cnt);
+
+ /*
+ * allocate and initialize data arrays
+ */
+ array_A =(PRInt32 *) PR_MALLOC(sizeof(PRInt32) * TEST_ARRAY_SIZE);
+ array_B =(PRInt32 *) PR_MALLOC(sizeof(PRInt32) * TEST_ARRAY_SIZE);
+ array_C =(PRInt32 *) PR_MALLOC(sizeof(PRInt32) * TEST_ARRAY_SIZE);
+ cnt = 0;
+ for (i=0; i < TEST_ARRAY_SIZE; i++) {
+ array_A[i] = cnt++;
+ array_B[i] = cnt++;
+ array_C[i] = array_A[i] + array_B[i];
+ }
+
+ if (_debug_on)
+ PR_fprintf(output,"%s: thread_cnt = %d loop_cnt = %d\n", argv[0],
+ thread_cnt, loop_cnt);
+ for(cnt = 0; cnt < thread_cnt; cnt++) {
+ PRThreadScope scope;
+
+ params[cnt].rwlock = rwlock1;
+ params[cnt].loop_cnt = loop_cnt;
+
+ /*
+ * create LOCAL and GLOBAL threads alternately
+ */
+ if (cnt & 1) {
+ scope = PR_LOCAL_THREAD;
+ }
+ else {
+ scope = PR_GLOBAL_THREAD;
+ }
+
+ threads[cnt] = PR_CreateThread(PR_USER_THREAD,
+ rwtest, &params[cnt],
+ PR_PRIORITY_NORMAL,
+ scope,
+ PR_JOINABLE_THREAD,
+ 0);
+ if (threads[cnt] == NULL) {
+ PR_fprintf(errhandle, "PR_CreateThread failed - error %d\n",
+ PR_GetError());
+ PR_ProcessExit(2);
+ }
+ if (_debug_on)
+ PR_fprintf(output,"%s: created thread = %p\n", argv[0],
+ threads[cnt]);
+ }
+
+ for(cnt = 0; cnt < thread_cnt; cnt++) {
+ rc = PR_JoinThread(threads[cnt]);
+ PR_ASSERT(rc == PR_SUCCESS);
+
+ }
+
+ PR_DELETE(threads);
+ PR_DELETE(params);
+
+ PR_DELETE(array_A);
+ PR_DELETE(array_B);
+ PR_DELETE(array_C);
+
+ PR_DestroyRWLock(rwlock1);
+
+
+ printf("PASS\n");
+ return 0;
+}
+
+static void rwtest(void *args)
+{
+ PRInt32 index;
+ thread_args *arg = (thread_args *) args;
+
+
+ for (index = 0; index < arg->loop_cnt; index++) {
+
+ /*
+ * verify sum, update arrays and verify sum again
+ */
+
+ PR_RWLock_Rlock(arg->rwlock);
+ check_array();
+ PR_RWLock_Unlock(arg->rwlock);
+
+ PR_RWLock_Wlock(arg->rwlock);
+ update_array();
+ PR_RWLock_Unlock(arg->rwlock);
+
+ PR_RWLock_Rlock(arg->rwlock);
+ check_array();
+ PR_RWLock_Unlock(arg->rwlock);
+ }
+ if (_debug_on)
+ PR_fprintf(output,
+ "Thread[0x%x] lock = 0x%x exiting\n",
+ PR_GetCurrentThread(), arg->rwlock);
+
+}
+
+static void check_array(void)
+{
+ PRInt32 i;
+
+ for (i=0; i < TEST_ARRAY_SIZE; i++)
+ if (array_C[i] != (array_A[i] + array_B[i])) {
+ PR_fprintf(output, "Error - data check failed\n");
+ PR_ProcessExit(1);
+ }
+}
+
+static void update_array(void)
+{
+ PRInt32 i;
+
+ for (i=0; i < TEST_ARRAY_SIZE; i++) {
+ array_A[i] += i;
+ array_B[i] -= i;
+ }
+}
diff --git a/nsprpub/pr/tests/sel_spd.c b/nsprpub/pr/tests/sel_spd.c
new file mode 100644
index 0000000000..6e3f66fedd
--- /dev/null
+++ b/nsprpub/pr/tests/sel_spd.c
@@ -0,0 +1,534 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * Test the speed of select within NSPR
+ *
+ */
+
+#include "nspr.h"
+#include "prpriv.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+
+#if defined(XP_UNIX)
+#include <unistd.h>
+#endif
+
+#ifdef DEBUG
+#define PORT_INC_DO +100
+#else
+#define PORT_INC_DO
+#endif
+#ifdef IS_64
+#define PORT_INC_3264 +200
+#else
+#define PORT_INC_3264
+#endif
+
+#define PORT_BASE 19000 PORT_INC_DO PORT_INC_3264
+
+typedef struct timer_slot_t {
+ unsigned long d_connect;
+ unsigned long d_cl_data;
+ unsigned long d_sv_data;
+ unsigned long d_close;
+ unsigned long d_total;
+ unsigned long requests;
+} timer_slot_t;
+
+static long _iterations = 5;
+static long _client_data = 8192;
+
+static long _server_data = (128*1024);
+static long _threads_max = 10, _threads = 10;
+
+static int verbose=0;
+static PRMonitor *exit_cv;
+static long _thread_exit_count;
+static timer_slot_t *timer_data;
+static PRThreadScope scope1, scope2;
+
+void tally_results(int);
+
+/* return the diff in microseconds */
+unsigned long _delta(PRIntervalTime *start, PRIntervalTime *stop)
+{
+ /*
+ * Will C do the right thing with unsigned arithemtic?
+ */
+ return PR_IntervalToMicroseconds(*stop - *start);
+}
+
+int _readn(PRFileDesc *sock, char *buf, int len)
+{
+ int rem;
+ int bytes;
+
+ for (rem=len; rem; rem -= bytes) {
+ bytes = PR_Recv(sock, buf+len-rem, rem, 0, PR_INTERVAL_NO_TIMEOUT);
+ if (bytes <= 0) {
+ return -1;
+ }
+ }
+ return len;
+}
+
+void
+_thread_exit(int id)
+{
+ PR_EnterMonitor(exit_cv);
+#ifdef DEBUG
+ fprintf(stdout, "Thread %d EXIT\n", id);
+#endif
+
+ _thread_exit_count--;
+ if (_thread_exit_count == 0) {
+#ifdef DEBUG
+ fprintf(stdout, "Thread %d EXIT triggered notify\n", id);
+#endif
+ PR_Notify(exit_cv);
+ }
+ PR_ExitMonitor(exit_cv);
+}
+
+void
+_server_thread(void *arg_id)
+{
+ void _client_thread(void *);
+ int *id = (int *)arg_id;
+ PRFileDesc *sock;
+ PRSocketOptionData sockopt;
+ PRNetAddr sa;
+ PRFileDesc * newsock;
+ char *data_buffer = NULL;
+ int data_buffer_size;
+ int index;
+ PRIntervalTime start,
+ connect_done,
+ read_done,
+ write_done,
+ close_done;
+
+
+#ifdef DEBUG
+ fprintf(stdout, "server thread %d alive\n", *id);
+#endif
+
+ data_buffer_size = (_client_data>_server_data?_client_data:_server_data);
+
+ if ( (data_buffer = (char *)PR_Malloc(data_buffer_size * sizeof(char))) == NULL ) {
+ fprintf(stderr, "Error creating buffer in server thread %d\n", *id);
+ goto done;
+ }
+
+
+ if ( (sock = PR_NewTCPSocket()) == NULL) {
+ fprintf(stderr, "Error creating socket in server thread %d\n", *id);
+ goto done;
+ }
+
+ sockopt.option = PR_SockOpt_Reuseaddr;
+ sockopt.value.reuse_addr = PR_TRUE;
+ if ( PR_SetSocketOption(sock, &sockopt) == PR_FAILURE) {
+ fprintf(stderr, "Error setting socket option in server thread %d\n", *id);
+ goto done;
+ }
+
+ memset(&sa, 0, sizeof(sa));
+ sa.inet.family = PR_AF_INET;
+ sa.inet.port = PR_htons(PORT_BASE + *id);
+ sa.inet.ip = PR_htonl(PR_INADDR_ANY);
+
+ if ( PR_Bind(sock, &sa) < 0) {
+ fprintf(stderr, "Error binding socket in server thread %d errno = %d\n", *id, errno);
+ goto done;
+ }
+
+ if ( PR_Listen(sock, 32) < 0 ) {
+ fprintf(stderr, "Error listening to socket in server thread %d\n", *id);
+ goto done;
+ }
+
+ /* Tell the client to start */
+ if ( PR_CreateThread(PR_USER_THREAD,
+ _client_thread,
+ id,
+ PR_PRIORITY_NORMAL,
+ scope2,
+ PR_UNJOINABLE_THREAD,
+ 0) == NULL) {
+ fprintf(stderr, "Error creating client thread %d\n", *id);
+ }
+
+ for (index = 0; index< _iterations; index++) {
+
+#ifdef DEBUG
+ fprintf(stdout, "server thread %d loop %d\n", *id, index);
+#endif
+
+ start = PR_IntervalNow();
+
+ if ( (newsock = PR_Accept(sock, &sa,
+ PR_INTERVAL_NO_TIMEOUT)) == NULL) {
+ fprintf(stderr, "Error accepting connection %d in server thread %d\n",
+ index, *id);
+ goto done;
+ }
+#ifdef DEBUG
+ fprintf(stdout, "server thread %d got connection %d\n", *id, newsock);
+#endif
+
+
+ connect_done = PR_IntervalNow();
+
+ if ( _readn(newsock, data_buffer, _client_data) < _client_data) {
+ fprintf(stderr, "Error reading client data for iteration %d in server thread %d\n", index, *id );
+ goto done;
+ }
+
+#ifdef DEBUG
+ fprintf(stdout, "server thread %d read %d bytes\n", *id, _client_data);
+#endif
+ read_done = PR_IntervalNow();
+
+ if ( PR_Send(newsock, data_buffer, _server_data, 0,
+ PR_INTERVAL_NO_TIMEOUT) < _server_data) {
+ fprintf(stderr, "Error sending client data for iteration %d in server thread %d\n", index, *id );
+ goto done;
+ }
+
+#ifdef DEBUG
+ fprintf(stdout, "server thread %d write %d bytes\n", *id, _server_data);
+#endif
+
+ write_done = PR_IntervalNow();
+
+ PR_Close(newsock);
+
+ close_done = PR_IntervalNow();
+
+ timer_data[2*(*id)].d_connect += _delta(&start, &connect_done);
+ timer_data[2*(*id)].d_cl_data += _delta(&connect_done, &read_done);
+ timer_data[2*(*id)].d_sv_data += _delta(&read_done, &write_done);
+ timer_data[2*(*id)].d_close += _delta(&write_done, &close_done);
+ timer_data[2*(*id)].d_total += _delta(&start, &close_done);
+ timer_data[2*(*id)].requests++;
+
+
+#ifdef DEBUG
+ fprintf(stdout, "server: %d %d %d %d %d\n",
+ _delta(&start, &connect_done), _delta(&connect_done, &read_done),
+ _delta(&read_done, &write_done), _delta(&write_done, &close_done),
+ _delta(&start, &close_done));
+#endif
+ }
+
+done:
+ if (data_buffer != NULL) {
+ PR_Free (data_buffer);
+ }
+ if (sock) {
+ PR_Close(sock);
+ }
+ _thread_exit(*id);
+ return;
+}
+
+void
+_client_thread(void *arg_id)
+{
+ int *id = (int *)arg_id;
+ int index;
+ PRNetAddr sa;
+ PRFileDesc *sock_h;
+ char *data_buffer = NULL;
+ int data_buffer_size;
+ int bytes;
+ PRIntervalTime start,
+ connect_done,
+ read_done,
+ write_done,
+ close_done;
+ PRStatus rv;
+
+#ifdef DEBUG
+ fprintf(stdout, "client thread %d alive\n", *id);
+#endif
+
+ data_buffer_size = (_client_data>_server_data?_client_data:_server_data);
+
+ if ( (data_buffer = (char *)PR_Malloc(data_buffer_size * sizeof(char))) == NULL) {
+ fprintf(stderr, "Error creating buffer in server thread %d\n", *id);
+ goto done;
+ }
+
+ memset(&sa, 0, sizeof(sa));
+ rv = PR_InitializeNetAddr(PR_IpAddrLoopback, PORT_BASE + *id, &sa);
+ PR_ASSERT(PR_SUCCESS == rv);
+
+ for (index = 0; index< _iterations; index++) {
+
+#ifdef DEBUG
+ fprintf(stdout, "client thread %d loop %d\n", *id, index);
+#endif
+
+ start = PR_IntervalNow();
+ if ( (sock_h = PR_NewTCPSocket()) == NULL) {
+ fprintf(stderr, "Error creating socket %d in client thread %d\n",
+ index, *id);
+ goto done;
+ }
+
+#ifdef DEBUG
+ fprintf(stdout, "client thread %d socket created %d\n", *id, sock_h);
+#endif
+
+ if ( PR_Connect(sock_h, &sa,
+ PR_INTERVAL_NO_TIMEOUT) < 0) {
+ fprintf(stderr, "Error accepting connection %d in client thread %d\n",
+ index, *id);
+ goto done;
+ }
+
+#ifdef DEBUG
+ fprintf(stdout, "client thread %d socket connected %d\n", *id, sock_h);
+#endif
+
+ connect_done = PR_IntervalNow();
+ if ( PR_Send(sock_h, data_buffer, _client_data, 0,
+ PR_INTERVAL_NO_TIMEOUT) < _client_data) {
+ fprintf(stderr, "Error sending client data for iteration %d in client thread %d\n", index, *id );
+ goto done;
+ }
+
+#ifdef DEBUG
+ fprintf(stdout, "client thread %d socket wrote %d\n", *id, _client_data);
+#endif
+
+ write_done = PR_IntervalNow();
+ if ( (bytes = _readn(sock_h, data_buffer, _server_data)) < _server_data) {
+ fprintf(stderr, "Error reading server data for iteration %d in client thread %d (read %d bytes)\n", index, *id, bytes );
+ goto done;
+ }
+
+#ifdef DEBUG
+ fprintf(stdout, "client thread %d socket read %d\n", *id, _server_data);
+#endif
+
+ read_done = PR_IntervalNow();
+ PR_Close(sock_h);
+ close_done = PR_IntervalNow();
+
+ timer_data[2*(*id)+1].d_connect += _delta(&start, &connect_done);
+ timer_data[2*(*id)+1].d_cl_data += _delta(&connect_done, &write_done);
+ timer_data[2*(*id)+1].d_sv_data += _delta(&write_done, &read_done);
+ timer_data[2*(*id)+1].d_close += _delta(&read_done, &close_done);
+ timer_data[2*(*id)+1].d_total += _delta(&start, &close_done);
+ timer_data[2*(*id)+1].requests++;
+ }
+done:
+ if (data_buffer != NULL) {
+ PR_Free (data_buffer);
+ }
+ _thread_exit(*id);
+
+ return;
+}
+
+static
+void do_work(void)
+{
+ int index;
+
+ _thread_exit_count = _threads * 2;
+ for (index=0; index<_threads; index++) {
+ int *id = (int *)PR_Malloc(sizeof(int));
+
+ *id = index;
+
+ if ( PR_CreateThread(PR_USER_THREAD,
+ _server_thread,
+ id,
+ PR_PRIORITY_NORMAL,
+ scope1,
+ PR_UNJOINABLE_THREAD,
+ 0) == NULL) {
+ fprintf(stderr, "Error creating server thread %d\n", index);
+ }
+ }
+
+ PR_EnterMonitor(exit_cv);
+ while (_thread_exit_count > 0) {
+ PR_Wait(exit_cv, PR_INTERVAL_NO_TIMEOUT);
+ }
+ PR_ExitMonitor(exit_cv);
+
+ fprintf(stdout, "TEST COMPLETE!\n");
+
+ tally_results(verbose);
+
+}
+
+static void do_workUU(void)
+{
+ scope1 = PR_LOCAL_THREAD;
+ scope2 = PR_LOCAL_THREAD;
+ do_work();
+}
+
+static void do_workUK(void)
+{
+ scope1 = PR_LOCAL_THREAD;
+ scope2 = PR_GLOBAL_THREAD;
+ do_work();
+}
+
+static void do_workKU(void)
+{
+ scope1 = PR_GLOBAL_THREAD;
+ scope2 = PR_LOCAL_THREAD;
+ do_work();
+}
+
+static void do_workKK(void)
+{
+ scope1 = PR_GLOBAL_THREAD;
+ scope2 = PR_GLOBAL_THREAD;
+ do_work();
+}
+
+
+
+static void Measure(void (*func)(void), const char *msg)
+{
+ PRIntervalTime start, stop;
+ double d;
+
+ start = PR_IntervalNow();
+ (*func)();
+ stop = PR_IntervalNow();
+
+ d = (double)PR_IntervalToMicroseconds(stop - start);
+
+ printf("%40s: %6.2f usec\n", msg, d / _iterations);
+}
+
+
+int main(int argc, char **argv)
+{
+#if defined(XP_UNIX) || defined(XP_OS2)
+ int opt;
+ PR_IMPORT_DATA(char *) optarg;
+#endif
+
+#if defined(XP_UNIX) || defined(XP_OS2)
+ while ( (opt = getopt(argc, argv, "c:s:i:t:v")) != EOF) {
+ switch(opt) {
+ case 'i':
+ _iterations = atoi(optarg);
+ break;
+ case 't':
+ _threads_max = _threads = atoi(optarg);
+ break;
+ case 'c':
+ _client_data = atoi(optarg);
+ break;
+ case 's':
+ _server_data = atoi(optarg);
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ default:
+ break;
+ }
+ }
+#endif
+
+ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
+ PR_STDIO_INIT();
+
+ fprintf(stdout, "Running test for %d iterations with %d simultaneous threads.\n",
+ _iterations, _threads);
+ fprintf(stdout, "\tWill send %d bytes of client data and %d bytes of server data\n",
+ _client_data, _server_data);
+
+ if ( (exit_cv = PR_NewMonitor()) == NULL) {
+ fprintf(stderr, "Error creating monitor for exit cv\n");
+ }
+ if ( (timer_data = (timer_slot_t *)PR_Malloc(2*_threads * sizeof(timer_slot_t))) == NULL) {
+ fprintf(stderr, "error allocating thread time results array\n");
+ }
+ memset(timer_data, 0, 2*_threads*sizeof(timer_slot_t));
+
+ Measure(do_workUU, "select loop user/user");
+ Measure(do_workUK, "select loop user/kernel");
+ Measure(do_workKU, "select loop kernel/user");
+ Measure(do_workKK, "select loop kernel/kernel");
+
+
+ return 0;
+}
+
+void
+tally_results(int verbose)
+{
+ int index;
+ unsigned long tot_connect = 0;
+ unsigned long tot_cl_data = 0;
+ unsigned long tot_sv_data = 0;
+ unsigned long tot_close = 0;
+ unsigned long tot_all = 0;
+ unsigned long tot_requests = 0;
+
+ fprintf(stdout, "Server results:\n\n");
+ for (index=0; index<_threads_max*2; index+=2) {
+
+ if (verbose)
+ fprintf(stdout, "server thread %u\t%u\t%u\t%u\t%u\t%u\t%u\n",
+ index, timer_data[index].requests, timer_data[index].d_connect,
+ timer_data[index].d_cl_data, timer_data[index].d_sv_data,
+ timer_data[index].d_close, timer_data[index].d_total);
+
+ tot_connect += timer_data[index].d_connect / _threads;
+ tot_cl_data += timer_data[index].d_cl_data / _threads;
+ tot_sv_data += timer_data[index].d_sv_data / _threads;
+ tot_close += timer_data[index].d_close / _threads;
+ tot_all += timer_data[index].d_total / _threads;
+ tot_requests += timer_data[index].requests / _threads;
+ }
+ fprintf(stdout, "----------\n");
+ fprintf(stdout, "server per thread totals %u\t%u\t%u\t%u\t%u\n",
+ tot_requests, tot_connect, tot_cl_data, tot_sv_data, tot_close);
+ fprintf(stdout, "server per thread elapsed time %u\n", tot_all);
+ fprintf(stdout, "----------\n");
+
+ tot_connect = tot_cl_data = tot_sv_data = tot_close = tot_all = tot_requests = 0;
+ fprintf(stdout, "Client results:\n\n");
+ for (index=1; index<_threads_max*2; index+=2) {
+
+ if (verbose)
+ fprintf(stdout, "client thread %u\t%u\t%u\t%u\t%u\t%u\t%u\n",
+ index, timer_data[index].requests, timer_data[index].d_connect,
+ timer_data[index].d_cl_data, timer_data[index].d_sv_data,
+ timer_data[index].d_close, timer_data[index].d_total);
+
+ tot_connect += timer_data[index].d_connect / _threads;
+ tot_cl_data += timer_data[index].d_cl_data / _threads;
+ tot_sv_data += timer_data[index].d_sv_data / _threads;
+ tot_close += timer_data[index].d_close / _threads;
+ tot_all += timer_data[index].d_total / _threads;
+ tot_requests += timer_data[index].requests / _threads;
+ }
+ fprintf(stdout, "----------\n");
+ fprintf(stdout, "client per thread totals %u\t%u\t%u\t%u\t%u\n",
+ tot_requests, tot_connect, tot_cl_data, tot_sv_data, tot_close);
+ fprintf(stdout, "client per thread elapsed time %u\n", tot_all);
+}
+
diff --git a/nsprpub/pr/tests/selct_er.c b/nsprpub/pr/tests/selct_er.c
new file mode 100644
index 0000000000..0c5c46e08d
--- /dev/null
+++ b/nsprpub/pr/tests/selct_er.c
@@ -0,0 +1,200 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/***********************************************************************
+** 1997 - Netscape Communications Corporation
+**
+** Name: prselect_err.c
+**
+** Description: tests PR_Select with sockets Error condition functions.
+**
+** Modification History:
+** 14-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
+** The debug mode will print all of the printfs associated with this test.
+** The regress mode will be the default mode. Since the regress tool limits
+** the output to a one line status:PASS or FAIL,all of the printf statements
+** have been handled with an if (debug_mode) statement.
+** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to
+** recognize the return code from tha main program.
+***********************************************************************/
+
+/***********************************************************************
+** Includes
+***********************************************************************/
+/* Used to get the command line option */
+#include "plgetopt.h"
+
+#include "primpl.h"
+#include "pprio.h"
+#include "prnetdb.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+
+PRIntn failed_already=0;
+PRIntn debug_mode;
+
+int main(int argc, char **argv)
+{
+ PRFileDesc *listenSock1, *listenSock2;
+ PRFileDesc *badFD;
+ PRUint16 listenPort1, listenPort2;
+ PRNetAddr addr;
+ PR_fd_set readFdSet;
+ char buf[128];
+ PRInt32 retVal;
+
+ /* The command line argument: -d is used to determine if the test is being run
+ in debug mode. The regress tool requires only one line output:PASS or FAIL.
+ All of the printfs associated with this test has been handled with a if (debug_mode)
+ test.
+ Usage: test_name -d
+ */
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "d:");
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 'd': /* debug mode */
+ debug_mode = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ /* main test */
+
+ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
+ PR_STDIO_INIT();
+
+ if (debug_mode) {
+ printf("This program tests PR_Select with sockets. Error\n");
+ printf("reporting operations are tested.\n\n");
+ }
+
+ /* Create two listening sockets */
+ if ((listenSock1 = PR_NewTCPSocket()) == NULL) {
+ fprintf(stderr, "Can't create a new TCP socket\n");
+ failed_already=1;
+ goto exit_now;
+ }
+ addr.inet.family = AF_INET;
+ addr.inet.ip = PR_htonl(INADDR_ANY);
+ addr.inet.port = PR_htons(0);
+ if (PR_Bind(listenSock1, &addr) == PR_FAILURE) {
+ fprintf(stderr, "Can't bind socket\n");
+ failed_already=1;
+ goto exit_now;
+ }
+ if (PR_GetSockName(listenSock1, &addr) == PR_FAILURE) {
+ fprintf(stderr, "PR_GetSockName failed\n");
+ failed_already=1;
+ goto exit_now;
+ }
+ listenPort1 = PR_ntohs(addr.inet.port);
+ if (PR_Listen(listenSock1, 5) == PR_FAILURE) {
+ fprintf(stderr, "Can't listen on a socket\n");
+ failed_already=1;
+ goto exit_now;
+ }
+
+ if ((listenSock2 = PR_NewTCPSocket()) == NULL) {
+ fprintf(stderr, "Can't create a new TCP socket\n");
+ failed_already=1;
+ goto exit_now;
+ }
+ addr.inet.family = AF_INET;
+ addr.inet.ip = PR_htonl(INADDR_ANY);
+ addr.inet.port = PR_htons(0);
+ if (PR_Bind(listenSock2, &addr) == PR_FAILURE) {
+ fprintf(stderr, "Can't bind socket\n");
+ failed_already=1;
+ goto exit_now;
+ }
+ if (PR_GetSockName(listenSock2, &addr) == PR_FAILURE) {
+ fprintf(stderr, "PR_GetSockName failed\n");
+ failed_already=1;
+ goto exit_now;
+ }
+ listenPort2 = PR_ntohs(addr.inet.port);
+ if (PR_Listen(listenSock2, 5) == PR_FAILURE) {
+ fprintf(stderr, "Can't listen on a socket\n");
+ failed_already=1;
+ goto exit_now;
+ }
+ PR_snprintf(buf, sizeof(buf),
+ "The server thread is listening on ports %hu and %hu\n\n",
+ listenPort1, listenPort2);
+ if (debug_mode) {
+ printf("%s", buf);
+ }
+
+ /* Set up the fd set */
+ PR_FD_ZERO(&readFdSet);
+ PR_FD_SET(listenSock1, &readFdSet);
+ PR_FD_SET(listenSock2, &readFdSet);
+
+
+ /* Testing bad fd */
+ if (debug_mode) {
+ printf("PR_Select should detect a bad file descriptor\n");
+ }
+ if ((badFD = PR_NewTCPSocket()) == NULL) {
+ fprintf(stderr, "Can't create a TCP socket\n");
+ failed_already=1;
+ goto exit_now;
+ }
+
+ PR_FD_SET(badFD, &readFdSet);
+ /*
+ * Make the fd invalid
+ */
+#if defined(XP_UNIX)
+ close(PR_FileDesc2NativeHandle(badFD));
+#elif defined(XP_OS2)
+ soclose(PR_FileDesc2NativeHandle(badFD));
+#elif defined(WIN32) || defined(WIN16)
+ closesocket(PR_FileDesc2NativeHandle(badFD));
+#else
+#error "Unknown architecture"
+#endif
+
+ retVal = PR_Select(0 /* unused */, &readFdSet, NULL, NULL,
+ PR_INTERVAL_NO_TIMEOUT);
+ if (retVal != -1 || PR_GetError() != PR_BAD_DESCRIPTOR_ERROR) {
+ fprintf(stderr, "Failed to detect the bad fd: "
+ "PR_Select returns %d\n", retVal);
+ if (retVal == -1) {
+ fprintf(stderr, "Error %d, oserror %d\n", PR_GetError(),
+ PR_GetOSError());
+ failed_already=1;
+ }
+ goto exit_now;
+ }
+ if (debug_mode) {
+ printf("PR_Select detected a bad fd. Test passed.\n\n");
+ }
+ PR_FD_CLR(badFD, &readFdSet);
+
+ PR_Cleanup();
+ goto exit_now;
+exit_now:
+ if(failed_already) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+
+}
+
diff --git a/nsprpub/pr/tests/selct_nm.c b/nsprpub/pr/tests/selct_nm.c
new file mode 100644
index 0000000000..a698f0fa42
--- /dev/null
+++ b/nsprpub/pr/tests/selct_nm.c
@@ -0,0 +1,294 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/***********************************************************************
+** 1997 - Netscape Communications Corporation
+**
+** Name: prselect_norm.c
+**
+** Description: tests PR_Select with sockets - Normal operations.
+**
+** Modification History:
+** 14-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
+** The debug mode will print all of the printfs associated with this test.
+** The regress mode will be the default mode. Since the regress tool limits
+** the output to a one line status:PASS or FAIL,all of the printf statements
+** have been handled with an if (debug_mode) statement.
+** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to
+** recognize the return code from tha main program.
+***********************************************************************/
+
+/***********************************************************************
+** Includes
+***********************************************************************/
+/* Used to get the command line option */
+#include "plgetopt.h"
+
+#include "prinit.h"
+#include "prio.h"
+#include "prlog.h"
+#include "prprf.h"
+#include "prerror.h"
+#include "prnetdb.h"
+
+#include "obsolete/probslet.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+PRIntn failed_already=0;
+PRIntn debug_mode;
+
+static void
+clientThreadFunc(void *arg)
+{
+ PRUintn port = (PRUintn) arg;
+ PRFileDesc *sock;
+ PRNetAddr addr;
+ char buf[128];
+ int i;
+
+ addr.inet.family = PR_AF_INET;
+ addr.inet.port = PR_htons((PRUint16)port);
+ addr.inet.ip = PR_htonl(PR_INADDR_LOOPBACK);
+ PR_snprintf(buf, sizeof(buf), "%hu", addr.inet.port);
+
+ for (i = 0; i < 5; i++) {
+ sock = PR_NewTCPSocket();
+ PR_Connect(sock, &addr, PR_INTERVAL_NO_TIMEOUT);
+ PR_Write(sock, buf, sizeof(buf));
+ PR_Close(sock);
+ }
+}
+
+int main(int argc, char **argv)
+{
+ PRFileDesc *listenSock1, *listenSock2;
+ PRFileDesc *fds0[10], *fds1[10], **fds, **other_fds;
+ PRIntn nfds;
+ PRUint16 listenPort1, listenPort2;
+ PRNetAddr addr;
+ PR_fd_set readFdSet;
+ char buf[128];
+ PRThread *clientThread;
+ PRInt32 retVal;
+ PRIntn i, j;
+
+ /* The command line argument: -d is used to determine if the test is being run
+ in debug mode. The regress tool requires only one line output:PASS or FAIL.
+ All of the printfs associated with this test has been handled with a if (debug_mode)
+ test.
+ Usage: test_name -d
+ */
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "d:");
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 'd': /* debug mode */
+ debug_mode = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ /* main test */
+
+ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
+ PR_STDIO_INIT();
+
+ if (debug_mode) {
+ printf("This program tests PR_Select with sockets. \n");
+ printf(" Normal operation are tested.\n\n");
+ }
+
+ /* Create two listening sockets */
+ if ((listenSock1 = PR_NewTCPSocket()) == NULL) {
+ fprintf(stderr, "Can't create a new TCP socket\n");
+ failed_already=1;
+ goto exit_now;
+ }
+ addr.inet.family = PR_AF_INET;
+ addr.inet.ip = PR_htonl(PR_INADDR_ANY);
+ addr.inet.port = PR_htons(0);
+ if (PR_Bind(listenSock1, &addr) == PR_FAILURE) {
+ fprintf(stderr, "Can't bind socket\n");
+ failed_already=1;
+ goto exit_now;
+ }
+ if (PR_GetSockName(listenSock1, &addr) == PR_FAILURE) {
+ fprintf(stderr, "PR_GetSockName failed\n");
+ failed_already=1;
+ goto exit_now;
+ }
+ listenPort1 = PR_ntohs(addr.inet.port);
+ if (PR_Listen(listenSock1, 5) == PR_FAILURE) {
+ fprintf(stderr, "Can't listen on a socket\n");
+ failed_already=1;
+ goto exit_now;
+ }
+
+ if ((listenSock2 = PR_NewTCPSocket()) == NULL) {
+ fprintf(stderr, "Can't create a new TCP socket\n");
+ failed_already=1;
+ goto exit_now;
+ }
+ addr.inet.family = PR_AF_INET;
+ addr.inet.ip = PR_htonl(PR_INADDR_ANY);
+ addr.inet.port = PR_htons(0);
+ if (PR_Bind(listenSock2, &addr) == PR_FAILURE) {
+ fprintf(stderr, "Can't bind socket\n");
+ failed_already=1;
+ goto exit_now;
+ }
+ if (PR_GetSockName(listenSock2, &addr) == PR_FAILURE) {
+ fprintf(stderr, "PR_GetSockName failed\n");
+ failed_already=1;
+ goto exit_now;
+ }
+ listenPort2 = PR_ntohs(addr.inet.port);
+ if (PR_Listen(listenSock2, 5) == PR_FAILURE) {
+ fprintf(stderr, "Can't listen on a socket\n");
+ failed_already=1;
+ goto exit_now;
+ }
+ PR_snprintf(buf, sizeof(buf),
+ "The server thread is listening on ports %hu and %hu\n\n",
+ listenPort1, listenPort2);
+ if (debug_mode) {
+ printf("%s", buf);
+ }
+
+ clientThread = PR_CreateThread(PR_USER_THREAD,
+ clientThreadFunc, (void *) listenPort1,
+ PR_PRIORITY_NORMAL, PR_LOCAL_THREAD,
+ PR_UNJOINABLE_THREAD, 0);
+ if (clientThread == NULL) {
+ fprintf(stderr, "can't create thread\n");
+ failed_already=1;
+ goto exit_now;
+ }
+
+ clientThread = PR_CreateThread(PR_USER_THREAD,
+ clientThreadFunc, (void *) listenPort2,
+ PR_PRIORITY_NORMAL, PR_LOCAL_THREAD,
+ PR_UNJOINABLE_THREAD, 0);
+ if (clientThread == NULL) {
+ fprintf(stderr, "can't create thread\n");
+ failed_already=1;
+ goto exit_now;
+ }
+
+ if (debug_mode) {
+ printf("Two client threads are created. Each of them will\n");
+ printf("send data to one of the two ports the server is listening on.\n");
+ printf("The data they send is the port number. Each of them send\n");
+ printf("the data five times, so you should see ten lines below,\n");
+ printf("interleaved in an arbitrary order.\n");
+ }
+ /* set up the fd array */
+ fds = fds0;
+ other_fds = fds1;
+ fds[0] = listenSock1;
+ fds[1] = listenSock2;
+ nfds = 2;
+ /* Set up the fd set */
+ PR_FD_ZERO(&readFdSet);
+ PR_FD_SET(listenSock1, &readFdSet);
+ PR_FD_SET(listenSock2, &readFdSet);
+
+ /* 20 events total */
+ i = 0;
+ while (i < 20) {
+ PRFileDesc **tmp;
+ int nextIndex;
+ int nEvents = 0;
+
+ retVal = PR_Select(0 /* unused */, &readFdSet, NULL, NULL,
+ PR_INTERVAL_NO_TIMEOUT);
+ PR_ASSERT(retVal != 0); /* no timeout */
+ if (retVal == -1) {
+ fprintf(stderr, "PR_Select failed (%d, %d)\n", PR_GetError(),
+ PR_GetOSError());
+ failed_already=1;
+ goto exit_now;
+ }
+
+ nextIndex = 2;
+ /* the two listening sockets */
+ for (j = 0; j < 2; j++) {
+ other_fds[j] = fds[j];
+ if (PR_FD_ISSET(fds[j], &readFdSet)) {
+ PRFileDesc *sock;
+
+ nEvents++;
+ sock = PR_Accept(fds[j], NULL, PR_INTERVAL_NO_TIMEOUT);
+ if (sock == NULL) {
+ fprintf(stderr, "PR_Accept() failed\n");
+ failed_already=1;
+ goto exit_now;
+ }
+ other_fds[nextIndex] = sock;
+ PR_FD_SET(sock, &readFdSet);
+ nextIndex++;
+ }
+ PR_FD_SET(fds[j], &readFdSet);
+ }
+
+ for (j = 2; j < nfds; j++) {
+ if (PR_FD_ISSET(fds[j], &readFdSet)) {
+ PRInt32 nBytes;
+
+ PR_FD_CLR(fds[j], &readFdSet);
+ nEvents++;
+ nBytes = PR_Read(fds[j], buf, sizeof(buf));
+ if (nBytes == -1) {
+ fprintf(stderr, "PR_Read() failed\n");
+ failed_already=1;
+ goto exit_now;
+ }
+ /* Just to be safe */
+ buf[127] = '\0';
+ PR_Close(fds[j]);
+ if (debug_mode) {
+ printf("The server received \"%s\" from a client\n", buf);
+ }
+ } else {
+ PR_FD_SET(fds[j], &readFdSet);
+ other_fds[nextIndex] = fds[j];
+ nextIndex++;
+ }
+ }
+
+ PR_ASSERT(retVal == nEvents);
+ /* swap */
+ tmp = fds;
+ fds = other_fds;
+ other_fds = tmp;
+ nfds = nextIndex;
+ i += nEvents;
+ }
+
+ if (debug_mode) {
+ printf("Test passed\n");
+ }
+
+ PR_Cleanup();
+ goto exit_now;
+exit_now:
+ if(failed_already) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+}
diff --git a/nsprpub/pr/tests/selct_to.c b/nsprpub/pr/tests/selct_to.c
new file mode 100644
index 0000000000..76ac99b2e1
--- /dev/null
+++ b/nsprpub/pr/tests/selct_to.c
@@ -0,0 +1,182 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/***********************************************************************
+** 1997 - Netscape Communications Corporation
+**
+** Name: prselect_to.c
+**
+** Description: tests PR_Select with sockets. Time out functions
+**
+** Modification History:
+** 14-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
+** The debug mode will print all of the printfs associated with this test.
+** The regress mode will be the default mode. Since the regress tool limits
+** the output to a one line status:PASS or FAIL,all of the printf statements
+** have been handled with an if (debug_mode) statement.
+** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to
+** recognize the return code from tha main program.
+***********************************************************************/
+
+/***********************************************************************
+** Includes
+***********************************************************************/
+/* Used to get the command line option */
+#include "plgetopt.h"
+
+#include "prinit.h"
+#include "prio.h"
+#include "prlog.h"
+#include "prprf.h"
+#include "prnetdb.h"
+
+#include "obsolete/probslet.h"
+
+#include "prerror.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+PRIntn failed_already=0;
+PRIntn debug_mode;
+
+int main(int argc, char **argv)
+{
+ PRFileDesc *listenSock1, *listenSock2;
+ PRUint16 listenPort1, listenPort2;
+ PRNetAddr addr;
+ PR_fd_set readFdSet;
+ char buf[128];
+ PRInt32 retVal;
+
+ /* The command line argument: -d is used to determine if the test is being run
+ in debug mode. The regress tool requires only one line output:PASS or FAIL.
+ All of the printfs associated with this test has been handled with a if (debug_mode)
+ test.
+ Usage: test_name -d
+ */
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "d:");
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 'd': /* debug mode */
+ debug_mode = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ /* main test */
+
+ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
+ PR_STDIO_INIT();
+
+ if (debug_mode) {
+ printf("This program tests PR_Select with sockets. Timeout \n");
+ printf("operations are tested.\n\n");
+ }
+
+ /* Create two listening sockets */
+ if ((listenSock1 = PR_NewTCPSocket()) == NULL) {
+ fprintf(stderr, "Can't create a new TCP socket\n");
+ failed_already=1;
+ goto exit_now;
+ }
+ addr.inet.family = PR_AF_INET;
+ addr.inet.ip = PR_htonl(PR_INADDR_ANY);
+ addr.inet.port = PR_htons(0);
+ if (PR_Bind(listenSock1, &addr) == PR_FAILURE) {
+ fprintf(stderr, "Can't bind socket\n");
+ failed_already=1;
+ goto exit_now;
+ }
+ if (PR_GetSockName(listenSock1, &addr) == PR_FAILURE) {
+ fprintf(stderr, "PR_GetSockName failed\n");
+ failed_already=1;
+ goto exit_now;
+ }
+ listenPort1 = PR_ntohs(addr.inet.port);
+ if (PR_Listen(listenSock1, 5) == PR_FAILURE) {
+ fprintf(stderr, "Can't listen on a socket\n");
+ failed_already=1;
+ goto exit_now;
+ }
+
+ if ((listenSock2 = PR_NewTCPSocket()) == NULL) {
+ fprintf(stderr, "Can't create a new TCP socket\n");
+ failed_already=1;
+ goto exit_now;
+ }
+ addr.inet.family = PR_AF_INET;
+ addr.inet.ip = PR_htonl(PR_INADDR_ANY);
+ addr.inet.port = PR_htons(0);
+ if (PR_Bind(listenSock2, &addr) == PR_FAILURE) {
+ fprintf(stderr, "Can't bind socket\n");
+ failed_already=1;
+ goto exit_now;
+ }
+ if (PR_GetSockName(listenSock2, &addr) == PR_FAILURE) {
+ fprintf(stderr, "PR_GetSockName failed\n");
+ failed_already=1;
+ goto exit_now;
+ }
+ listenPort2 = PR_ntohs(addr.inet.port);
+ if (PR_Listen(listenSock2, 5) == PR_FAILURE) {
+ fprintf(stderr, "Can't listen on a socket\n");
+ failed_already=1;
+ goto exit_now;
+ }
+ PR_snprintf(buf, sizeof(buf),
+ "The server thread is listening on ports %hu and %hu\n\n",
+ listenPort1, listenPort2);
+ if (debug_mode) {
+ printf("%s", buf);
+ }
+
+ /* Set up the fd set */
+ PR_FD_ZERO(&readFdSet);
+ PR_FD_SET(listenSock1, &readFdSet);
+ PR_FD_SET(listenSock2, &readFdSet);
+
+ /* Testing timeout */
+ if (debug_mode) {
+ printf("PR_Select should time out in 5 seconds\n");
+ }
+ retVal = PR_Select(0 /* unused */, &readFdSet, NULL, NULL,
+ PR_SecondsToInterval(5));
+ if (retVal != 0) {
+ PR_snprintf(buf, sizeof(buf),
+ "PR_Select should time out and return 0, but it returns %ld\n",
+ retVal);
+ fprintf(stderr, "%s", buf);
+ if (retVal == -1) {
+ fprintf(stderr, "Error %d, oserror %d\n", PR_GetError(),
+ PR_GetOSError());
+ failed_already=1;
+ }
+ goto exit_now;
+ }
+ if (debug_mode) {
+ printf("PR_Select timed out. Test passed.\n\n");
+ }
+
+ PR_Cleanup();
+
+exit_now:
+ if(failed_already) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+}
diff --git a/nsprpub/pr/tests/select2.c b/nsprpub/pr/tests/select2.c
new file mode 100644
index 0000000000..da7360b025
--- /dev/null
+++ b/nsprpub/pr/tests/select2.c
@@ -0,0 +1,385 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/***********************************************************************
+**
+** Name: select2.c
+**
+** Description: Measure PR_Select and Empty_Select performance.
+**
+** Modification History:
+** 20-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
+** The debug mode will print all of the printfs associated with this test.
+** The regress mode will be the default mode. Since the regress tool limits
+** the output to a one line status:PASS or FAIL,all of the printf statements
+** have been handled with an if (debug_mode) statement.
+***********************************************************************/
+
+/***********************************************************************
+** Includes
+***********************************************************************/
+/* Used to get the command line option */
+#include "plgetopt.h"
+#include "prttools.h"
+#include "primpl.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#if defined(OS2)
+#include <sys/time.h>
+#endif
+
+#define PORT 8000
+#define DEFAULT_COUNT 10
+PRInt32 count;
+
+
+/***********************************************************************
+** PRIVATE FUNCTION: Test_Result
+** DESCRIPTION: Used in conjunction with the regress tool, prints out the
+** status of the test case.
+** INPUTS: PASS/FAIL
+** OUTPUTS: None
+** RETURN: None
+** SIDE EFFECTS:
+**
+** RESTRICTIONS:
+** None
+** MEMORY: NA
+** ALGORITHM: Determine what the status is and print accordingly.
+**
+***********************************************************************/
+
+
+static void Test_Result (int result)
+{
+ switch (result)
+ {
+ case PASS:
+ printf ("PASS\n");
+ break;
+ case FAIL:
+ printf ("FAIL\n");
+ break;
+ default:
+ printf ("NOSTATUS\n");
+ break;
+ }
+}
+
+static void EmptyPRSelect(void)
+{
+ PRInt32 index = count;
+ PRInt32 rv;
+
+ for (; index--;) {
+ rv = PR_Select(0, NULL, NULL, NULL, PR_INTERVAL_NO_WAIT);
+ }
+}
+
+static void EmptyNativeSelect(void)
+{
+ PRInt32 rv;
+ PRInt32 index = count;
+ struct timeval timeout;
+
+ timeout.tv_sec = timeout.tv_usec = 0;
+ for (; index--;) {
+ rv = select(0, NULL, NULL, NULL, &timeout);
+ }
+}
+
+static void PRSelectTest(void)
+{
+ PRFileDesc *listenSocket;
+ PRNetAddr serverAddr;
+
+ if ( (listenSocket = PR_NewTCPSocket()) == NULL) {
+ if (debug_mode) {
+ printf("\tServer error creating listen socket\n");
+ }
+ return;
+ }
+
+ memset(&serverAddr, 0, sizeof(PRNetAddr));
+ serverAddr.inet.family = AF_INET;
+ serverAddr.inet.port = PR_htons(PORT);
+ serverAddr.inet.ip = PR_htonl(INADDR_ANY);
+
+ if ( PR_Bind(listenSocket, &serverAddr) == PR_FAILURE) {
+ if (debug_mode) {
+ printf("\tServer error binding to server address\n");
+ }
+ PR_Close(listenSocket);
+ return;
+ }
+
+ if ( PR_Listen(listenSocket, 128) == PR_FAILURE) {
+ if (debug_mode) {
+ printf("\tServer error listening to server socket\n");
+ }
+ PR_Close(listenSocket);
+ return;
+ }
+ if (debug_mode) {
+ printf("Listening on port %d\n", PORT);
+ }
+
+ {
+ PRFileDesc *newSock;
+ PRNetAddr rAddr;
+ PRInt32 loops = 0;
+ PR_fd_set rdset;
+ PRInt32 rv;
+ PRInt32 bytesRead;
+ char buf[11];
+
+ loops++;
+
+ if (debug_mode) {
+ printf("Going into accept\n");
+ }
+
+ newSock = PR_Accept(listenSocket,
+ &rAddr,
+ PR_INTERVAL_NO_TIMEOUT);
+
+ if (newSock) {
+ if (debug_mode) {
+ printf("Got connection!\n");
+ }
+ } else {
+ if (debug_mode) {
+ printf("PR_Accept failed: error code %d\n", PR_GetError());
+ }
+ else {
+ Test_Result (FAIL);
+ }
+ }
+
+ PR_FD_ZERO(&rdset);
+ PR_FD_SET(newSock, &rdset);
+
+ if (debug_mode) {
+ printf("Going into select \n");
+ }
+
+ rv = PR_Select(0, &rdset, 0, 0, PR_INTERVAL_NO_TIMEOUT);
+
+ if (debug_mode) {
+ printf("return from select is %d\n", rv);
+ }
+
+ if (PR_FD_ISSET(newSock, &rdset)) {
+ if (debug_mode) {
+ printf("I can't believe it- the socket is ready okay!\n");
+ }
+ } else {
+ if (debug_mode) {
+ printf("Damn; the select test failed...\n");
+ }
+ else {
+ Test_Result (FAIL);
+ }
+ }
+
+ strcpy(buf, "XXXXXXXXXX");
+ bytesRead = PR_Recv(newSock, buf, 10, 0, PR_INTERVAL_NO_TIMEOUT);
+ buf[10] = '\0';
+
+ if (debug_mode) {
+ printf("Recv completed with %d bytes, %s\n", bytesRead, buf);
+ }
+
+ PR_Close(newSock);
+ }
+
+}
+
+#if defined(XP_UNIX)
+
+static void NativeSelectTest(void)
+{
+ PRFileDesc *listenSocket;
+ PRNetAddr serverAddr;
+
+ if ( (listenSocket = PR_NewTCPSocket()) == NULL) {
+ if (debug_mode) {
+ printf("\tServer error creating listen socket\n");
+ }
+ return;
+ }
+
+ memset(&serverAddr, 0, sizeof(PRNetAddr));
+ serverAddr.inet.family = AF_INET;
+ serverAddr.inet.port = PR_htons(PORT);
+ serverAddr.inet.ip = PR_htonl(INADDR_ANY);
+
+ if ( PR_Bind(listenSocket, &serverAddr) == PR_FAILURE) {
+ if (debug_mode) {
+ printf("\tServer error binding to server address\n");
+ }
+ PR_Close(listenSocket);
+ return;
+ }
+
+ if ( PR_Listen(listenSocket, 128) == PR_FAILURE) {
+ if (debug_mode) {
+ printf("\tServer error listening to server socket\n");
+ }
+ PR_Close(listenSocket);
+ return;
+ }
+ if (debug_mode) {
+ printf("Listening on port %d\n", PORT);
+ }
+
+ {
+ PRIntn osfd;
+ char buf[11];
+ fd_set rdset;
+ PRNetAddr rAddr;
+ PRFileDesc *newSock;
+ struct timeval timeout;
+ PRInt32 bytesRead, rv, loops = 0;
+
+ loops++;
+
+ if (debug_mode) {
+ printf("Going into accept\n");
+ }
+
+ newSock = PR_Accept(listenSocket, &rAddr, PR_INTERVAL_NO_TIMEOUT);
+
+ if (newSock) {
+ if (debug_mode) {
+ printf("Got connection!\n");
+ }
+ } else {
+ if (debug_mode) {
+ printf("PR_Accept failed: error code %d\n", PR_GetError());
+ }
+ else {
+ Test_Result (FAIL);
+ }
+ }
+
+ osfd = PR_FileDesc2NativeHandle(newSock);
+ FD_ZERO(&rdset);
+ FD_SET(osfd, &rdset);
+
+ if (debug_mode) {
+ printf("Going into select \n");
+ }
+
+
+ timeout.tv_sec = 2; timeout.tv_usec = 0;
+ rv = select(osfd + 1, &rdset, NULL, NULL, &timeout);
+
+ if (debug_mode) {
+ printf("return from select is %d\n", rv);
+ }
+
+ if (FD_ISSET(osfd, &rdset)) {
+ if (debug_mode) {
+ printf("I can't believe it- the socket is ready okay!\n");
+ }
+ } else {
+ if (debug_mode) {
+ printf("Damn; the select test failed...\n");
+ }
+ else {
+ Test_Result (FAIL);
+ }
+ }
+
+ strcpy(buf, "XXXXXXXXXX");
+ bytesRead = PR_Recv(newSock, buf, 10, 0, PR_INTERVAL_NO_TIMEOUT);
+ buf[10] = '\0';
+
+ if (debug_mode) {
+ printf("Recv completed with %d bytes, %s\n", bytesRead, buf);
+ }
+
+ PR_Close(newSock);
+ }
+
+} /* NativeSelectTest */
+
+#endif /* defined(XP_UNIX) */
+
+/************************************************************************/
+
+static void Measure(void (*func)(void), const char *msg)
+{
+ PRIntervalTime start, stop;
+ double d;
+ PRInt32 tot;
+
+ start = PR_IntervalNow();
+ (*func)();
+ stop = PR_IntervalNow();
+
+ d = (double)PR_IntervalToMicroseconds(stop - start);
+ tot = PR_IntervalToMilliseconds(stop-start);
+
+ if (debug_mode) {
+ printf("%40s: %6.2f usec avg, %d msec total\n", msg, d / count, tot);
+ }
+}
+
+int main(int argc, char **argv)
+{
+
+ /* The command line argument: -d is used to determine if the test is being run
+ in debug mode. The regress tool requires only one line output:PASS or FAIL.
+ All of the printfs associated with this test has been handled with a if (debug_mode)
+ test.
+ Usage: test_name -d
+ */
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "d:");
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 'd': /* debug mode */
+ debug_mode = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ /* main test */
+
+ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
+ PR_STDIO_INIT();
+
+ if (argc > 2) {
+ count = atoi(argv[2]);
+ } else {
+ count = DEFAULT_COUNT;
+ }
+
+#if defined(XP_UNIX)
+ Measure(NativeSelectTest, "time to call 1 element select()");
+#endif
+ Measure(EmptyPRSelect, "time to call Empty PR_select()");
+ Measure(EmptyNativeSelect, "time to call Empty select()");
+ Measure(PRSelectTest, "time to call 1 element PR_select()");
+
+ if (!debug_mode) {
+ Test_Result (NOSTATUS);
+ }
+ PR_Cleanup();
+
+
+}
diff --git a/nsprpub/pr/tests/selintr.c b/nsprpub/pr/tests/selintr.c
new file mode 100644
index 0000000000..84513f6887
--- /dev/null
+++ b/nsprpub/pr/tests/selintr.c
@@ -0,0 +1,49 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * Test whether classic NSPR's select() wrapper properly blocks
+ * the periodic SIGALRM clocks. On some platforms (such as
+ * HP-UX and SINIX) an interrupted select() system call is
+ * restarted with the originally specified timeout, ignoring
+ * the time that has elapsed. If a select() call is interrupted
+ * repeatedly, it will never time out. (See Bugzilla bug #39674.)
+ */
+
+#if !defined(XP_UNIX)
+
+/*
+ * This test is applicable to Unix only.
+ */
+
+int main()
+{
+ return 0;
+}
+
+#else /* XP_UNIX */
+
+#include "nspr.h"
+
+#include <sys/time.h>
+#include <stdio.h>
+
+int main(int argc, char **argv)
+{
+ struct timeval timeout;
+ int rv;
+
+ PR_SetError(0, 0); /* force NSPR to initialize */
+ PR_EnableClockInterrupts();
+
+ /* 2 seconds timeout */
+ timeout.tv_sec = 2;
+ timeout.tv_usec = 0;
+ rv = select(1, NULL, NULL, NULL, &timeout);
+ printf("select returned %d\n", rv);
+ return 0;
+}
+
+#endif /* XP_UNIX */
diff --git a/nsprpub/pr/tests/sem.c b/nsprpub/pr/tests/sem.c
new file mode 100644
index 0000000000..80db76d2e9
--- /dev/null
+++ b/nsprpub/pr/tests/sem.c
@@ -0,0 +1,222 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/***********************************************************************
+**
+** Name: sem.c
+**
+** Description: Tests Semaphonre functions.
+**
+** Modification History:
+** 20-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
+** The debug mode will print all of the printfs associated with this test.
+** The regress mode will be the default mode. Since the regress tool limits
+** the output to a one line status:PASS or FAIL,all of the printf statements
+** have been handled with an if (debug_mode) statement.
+** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to
+** recognize the return code from tha main program.
+***********************************************************************/
+
+/***********************************************************************
+** Includes
+***********************************************************************/
+/* Used to get the command line option */
+#include "plgetopt.h"
+
+#include "nspr.h"
+#include "prpriv.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+PRIntn failed_already=0;
+PRIntn debug_mode;
+
+/*
+ Since we don't have stdin, stdout everywhere, we will fake
+ it with our in-memory buffers called stdin and stdout.
+*/
+
+#define SBSIZE 1024
+
+#include "obsolete/prsem.h"
+
+static char stdinBuf[SBSIZE];
+static char stdoutBuf[SBSIZE];
+
+static PRUintn stdinBufIdx = 0;
+static PRUintn stdoutBufIdx = 0;
+static PRStatus finalResult = PR_SUCCESS;
+
+
+static size_t dread (PRUintn device, char *buf, size_t bufSize)
+{
+ PRUintn i;
+
+ /* during first read call, initialize the stdinBuf buffer*/
+ if (stdinBufIdx == 0) {
+ for (i=0; i<SBSIZE; i++) {
+ stdinBuf[i] = i;
+ }
+ }
+
+ /* now copy data from stdinBuf to the given buffer upto bufSize */
+ for (i=0; i<bufSize; i++) {
+ if (stdinBufIdx == SBSIZE) {
+ break;
+ }
+ buf[i] = stdinBuf[stdinBufIdx++];
+ }
+
+ return i;
+}
+
+static size_t dwrite (PRUintn device, char *buf, size_t bufSize)
+{
+ PRUintn i, j;
+
+ /* copy data from the given buffer upto bufSize to stdoutBuf */
+ for (i=0; i<bufSize; i++) {
+ if (stdoutBufIdx == SBSIZE) {
+ break;
+ }
+ stdoutBuf[stdoutBufIdx++] = buf[i];
+ }
+
+ /* during last write call, compare the two buffers */
+ if (stdoutBufIdx == SBSIZE)
+ for (j=0; j<SBSIZE; j++)
+ if (stdinBuf[j] != stdoutBuf[j]) {
+ if (debug_mode) {
+ printf("data mismatch for index= %d \n", j);
+ }
+ finalResult = PR_FAILURE;
+ }
+
+ return i;
+}
+
+/*------------------ Following is the real test program ---------*/
+/*
+ Program to copy standard input to standard output. The program
+ uses two threads. One reads the input and puts the data in a
+ double buffer. The other reads the buffer contents and writes
+ it to standard output.
+*/
+
+PRSemaphore *emptyBufs; /* number of empty buffers */
+PRSemaphore *fullBufs; /* number of buffers that are full */
+
+#define BSIZE 100
+
+struct {
+ char data[BSIZE];
+ PRUintn nbytes; /* number of bytes in this buffer */
+} buf[2];
+
+static void PR_CALLBACK reader(void *arg)
+{
+ PRUintn i = 0;
+ size_t nbytes;
+
+ do {
+ (void) PR_WaitSem(emptyBufs);
+ nbytes = dread(0, buf[i].data, BSIZE);
+ buf[i].nbytes = nbytes;
+ PR_PostSem(fullBufs);
+ i = (i + 1) % 2;
+ } while (nbytes > 0);
+}
+
+static void writer(void)
+{
+ PRUintn i = 0;
+ size_t nbytes;
+
+ do {
+ (void) PR_WaitSem(fullBufs);
+ nbytes = buf[i].nbytes;
+ if (nbytes > 0) {
+ nbytes = dwrite(1, buf[i].data, nbytes);
+ PR_PostSem(emptyBufs);
+ i = (i + 1) % 2;
+ }
+ } while (nbytes > 0);
+}
+
+int main(int argc, char **argv)
+{
+ PRThread *r;
+
+ PR_STDIO_INIT();
+ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
+
+ {
+ /* The command line argument: -d is used to determine if the test is being run
+ in debug mode. The regress tool requires only one line output:PASS or FAIL.
+ All of the printfs associated with this test has been handled with a if (debug_mode)
+ test.
+ Usage: test_name -d
+ */
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "d:");
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 'd': /* debug mode */
+ debug_mode = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+ }
+
+ /* main test */
+
+ emptyBufs = PR_NewSem(2); /* two empty buffers */
+
+ fullBufs = PR_NewSem(0); /* zero full buffers */
+
+ /* create the reader thread */
+
+ r = PR_CreateThread(PR_USER_THREAD,
+ reader, 0,
+ PR_PRIORITY_NORMAL,
+ PR_LOCAL_THREAD,
+ PR_UNJOINABLE_THREAD,
+ 0);
+
+ /* Do the writer operation in this thread */
+ writer();
+
+ PR_DestroySem(emptyBufs);
+ PR_DestroySem(fullBufs);
+
+ if (finalResult == PR_SUCCESS) {
+ if (debug_mode) {
+ printf("sem Test Passed.\n");
+ }
+ }
+ else {
+ if (debug_mode) {
+ printf("sem Test Failed.\n");
+ }
+ failed_already=1;
+ }
+ PR_Cleanup();
+ if(failed_already) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+}
diff --git a/nsprpub/pr/tests/sema.c b/nsprpub/pr/tests/sema.c
new file mode 100644
index 0000000000..81ccd01b7a
--- /dev/null
+++ b/nsprpub/pr/tests/sema.c
@@ -0,0 +1,165 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nspr.h"
+#include "plgetopt.h"
+
+#include <stdio.h>
+
+#ifdef DEBUG
+#define SEM_D "D"
+#else
+#define SEM_D
+#endif
+#ifdef IS_64
+#define SEM_64 "64"
+#else
+#define SEM_64
+#endif
+
+#define SEM_NAME1 "/tmp/foo.sem" SEM_D SEM_64
+#define SEM_NAME2 "/tmp/bar.sem" SEM_D SEM_64
+#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_PostSemaphore 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_PostSemaphore 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/nsprpub/pr/tests/semaerr.c b/nsprpub/pr/tests/semaerr.c
new file mode 100644
index 0000000000..f3c253b4f4
--- /dev/null
+++ b/nsprpub/pr/tests/semaerr.c
@@ -0,0 +1,124 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nspr.h"
+#include "plgetopt.h"
+
+#include <stdio.h>
+
+#ifdef DEBUG
+#define SEM_D "D"
+#else
+#define SEM_D
+#endif
+#ifdef IS_64
+#define SEM_64 "64"
+#else
+#define SEM_64
+#endif
+
+#define NO_SUCH_SEM_NAME "/tmp/nosuchsem.sem" SEM_D SEM_64
+#define SEM_NAME1 "/tmp/foo.sem" SEM_D SEM_64
+#define EXE_NAME "semaerr1"
+#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++ = EXE_NAME;
+ 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/nsprpub/pr/tests/semaerr1.c b/nsprpub/pr/tests/semaerr1.c
new file mode 100644
index 0000000000..9271663d69
--- /dev/null
+++ b/nsprpub/pr/tests/semaerr1.c
@@ -0,0 +1,118 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nspr.h"
+#include "plgetopt.h"
+
+#include <stdio.h>
+
+#ifdef DEBUG
+#define SEM_D "D"
+#else
+#define SEM_D
+#endif
+#ifdef IS_64
+#define SEM_64 "64"
+#else
+#define SEM_64
+#endif
+
+#define SEM_NAME1 "/tmp/foo.sem" SEM_D SEM_64
+#define SEM_NAME2 "/tmp/bar.sem" SEM_D SEM_64
+#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/nsprpub/pr/tests/semaping.c b/nsprpub/pr/tests/semaping.c
new file mode 100644
index 0000000000..3b653d524e
--- /dev/null
+++ b/nsprpub/pr/tests/semaping.c
@@ -0,0 +1,187 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nspr.h"
+#include "plgetopt.h"
+
+#include <stdio.h>
+
+#ifdef DEBUG
+#define SEM_D "D"
+#else
+#define SEM_D
+#endif
+#ifdef IS_64
+#define SEM_64 "64"
+#else
+#define SEM_64
+#endif
+
+#define SHM_NAME "/tmp/counter" SEM_D SEM_64
+#define SEM_NAME1 "/tmp/foo.sem" SEM_D SEM_64
+#define SEM_NAME2 "/tmp/bar.sem" SEM_D SEM_64
+#define EXE_NAME "semapong"
+#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 (%d, %d)\n",
+ PR_GetError(), PR_GetOSError());
+ 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 (%d, %d)\n",
+ PR_GetError(), PR_GetOSError());
+ exit(1);
+ }
+
+ child_arg = &child_argv[0];
+ *child_arg++ = EXE_NAME;
+ 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_PostSemaphore 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/nsprpub/pr/tests/semapong.c b/nsprpub/pr/tests/semapong.c
new file mode 100644
index 0000000000..fd24824e31
--- /dev/null
+++ b/nsprpub/pr/tests/semapong.c
@@ -0,0 +1,130 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nspr.h"
+#include "plgetopt.h"
+
+#include <stdio.h>
+
+#ifdef DEBUG
+#define SEM_D "D"
+#else
+#define SEM_D
+#endif
+#ifdef IS_64
+#define SEM_64 "64"
+#else
+#define SEM_64
+#endif
+
+#define SHM_NAME "/tmp/counter" SEM_D SEM_64
+#define SEM_NAME1 "/tmp/foo.sem" SEM_D SEM_64
+#define SEM_NAME2 "/tmp/bar.sem" SEM_D SEM_64
+#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 (%d, %d)\n",
+ PR_GetError(), PR_GetOSError());
+ 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 (%d, %d)\n",
+ PR_GetError(), PR_GetOSError());
+ 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_PostSemaphore 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/nsprpub/pr/tests/sendzlf.c b/nsprpub/pr/tests/sendzlf.c
new file mode 100644
index 0000000000..a65f6cd6b4
--- /dev/null
+++ b/nsprpub/pr/tests/sendzlf.c
@@ -0,0 +1,214 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * Test: sendzlf.c
+ *
+ * Description: send a zero-length file with PR_SendFile and
+ * PR_TransmitFile.
+ */
+
+#define ZERO_LEN_FILE_NAME "zerolen.tmp"
+#define HEADER_STR "Header"
+#define HEADER_LEN 6 /* length of HEADER_STR, not counting the null byte */
+#define TRAILER_STR "Trailer"
+#define TRAILER_LEN 7 /* length of TRAILER_STR, not counting the null byte */
+
+#include "nspr.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static void ClientThread(void *arg)
+{
+ PRFileDesc *sock;
+ PRNetAddr addr;
+ PRUint16 port = (PRUint16) arg;
+ char buf[1024];
+ char *bufPtr;
+ PRInt32 nbytes;
+ PRInt32 ntotal;
+ PRInt32 nexpected;
+
+ sock = PR_NewTCPSocket();
+ if (NULL == sock) {
+ fprintf(stderr, "PR_NewTCPSocket failed\n");
+ exit(1);
+ }
+ if (PR_InitializeNetAddr(PR_IpAddrLoopback, port, &addr) == PR_FAILURE) {
+ fprintf(stderr, "PR_InitializeNetAddr failed\n");
+ exit(1);
+ }
+ if (PR_Connect(sock, &addr, PR_INTERVAL_NO_TIMEOUT) == PR_FAILURE) {
+ fprintf(stderr, "PR_Connect failed\n");
+ exit(1);
+ }
+ ntotal = 0;
+ bufPtr = buf;
+ while ((nbytes = PR_Read(sock, bufPtr, sizeof(buf)-ntotal)) > 0) {
+ ntotal += nbytes;
+ bufPtr += nbytes;
+ }
+ if (-1 == nbytes) {
+ fprintf(stderr, "PR_Read failed\n");
+ exit(1);
+ }
+ nexpected = HEADER_LEN+TRAILER_LEN+TRAILER_LEN+HEADER_LEN+HEADER_LEN;
+ if (ntotal != nexpected) {
+ fprintf(stderr, "total bytes read should be %d but is %d\n",
+ nexpected, ntotal);
+ exit(1);
+ }
+ if (memcmp(buf, HEADER_STR TRAILER_STR TRAILER_STR HEADER_STR HEADER_STR,
+ nexpected) != 0) {
+ fprintf(stderr, "wrong data is received\n");
+ exit(1);
+ }
+ if (PR_Close(sock) == PR_FAILURE) {
+ fprintf(stderr, "PR_Close failed\n");
+ exit(1);
+ }
+}
+
+static void ServerThread(void *arg)
+{
+ PRFileDesc *listenSock = (PRFileDesc *) arg;
+ PRFileDesc *acceptSock;
+ PRFileDesc *file;
+ PRSendFileData sfd;
+ char header[1024], trailer[1024];
+ PRInt32 nbytes;
+
+ /* Create a zero-length file */
+ file = PR_Open(ZERO_LEN_FILE_NAME,
+ PR_CREATE_FILE|PR_TRUNCATE|PR_RDWR, 0666);
+ if (NULL == file) {
+ fprintf(stderr, "PR_Open failed\n");
+ exit(1);
+ }
+ sfd.fd = file;
+ sfd.file_offset = 0;
+ sfd.file_nbytes = 0;
+ memcpy(header, HEADER_STR, HEADER_LEN);
+ memcpy(trailer, TRAILER_STR, TRAILER_LEN);
+ sfd.header = header;
+ sfd.hlen = HEADER_LEN;
+ sfd.trailer = trailer;
+ sfd.tlen = TRAILER_LEN;
+ acceptSock = PR_Accept(listenSock, NULL, PR_INTERVAL_NO_TIMEOUT);
+ if (NULL == acceptSock) {
+ fprintf(stderr, "PR_Accept failed\n");
+ exit(1);
+ }
+ /* Send both header and trailer */
+ nbytes = PR_SendFile(acceptSock, &sfd, PR_TRANSMITFILE_KEEP_OPEN,
+ PR_INTERVAL_NO_TIMEOUT);
+ if (HEADER_LEN+TRAILER_LEN != nbytes) {
+ fprintf(stderr, "PR_SendFile should return %d but returned %d\n",
+ HEADER_LEN+TRAILER_LEN, nbytes);
+ exit(1);
+ }
+ /* Trailer only, no header */
+ sfd.hlen = 0;
+ nbytes = PR_SendFile(acceptSock, &sfd, PR_TRANSMITFILE_KEEP_OPEN,
+ PR_INTERVAL_NO_TIMEOUT);
+ if (TRAILER_LEN != nbytes) {
+ fprintf(stderr, "PR_SendFile should return %d but returned %d\n",
+ TRAILER_LEN, nbytes);
+ exit(1);
+ }
+ /* Header only, no trailer */
+ sfd.hlen = HEADER_LEN;
+ sfd.tlen = 0;
+ nbytes = PR_SendFile(acceptSock, &sfd, PR_TRANSMITFILE_KEEP_OPEN,
+ PR_INTERVAL_NO_TIMEOUT);
+ if (HEADER_LEN != nbytes) {
+ fprintf(stderr, "PR_SendFile should return %d but returned %d\n",
+ HEADER_LEN, nbytes);
+ exit(1);
+ }
+ /* Try PR_TransmitFile */
+ nbytes = PR_TransmitFile(acceptSock, file, header, HEADER_LEN,
+ PR_TRANSMITFILE_KEEP_OPEN, PR_INTERVAL_NO_TIMEOUT);
+ if (HEADER_LEN != nbytes) {
+ fprintf(stderr, "PR_TransmitFile should return %d but returned %d\n",
+ HEADER_LEN, nbytes);
+ exit(1);
+ }
+ if (PR_Close(acceptSock) == PR_FAILURE) {
+ fprintf(stderr, "PR_Close failed\n");
+ exit(1);
+ }
+ if (PR_Close(file) == PR_FAILURE) {
+ fprintf(stderr, "PR_Close failed\n");
+ exit(1);
+ }
+ if (PR_Delete(ZERO_LEN_FILE_NAME) == PR_FAILURE) {
+ fprintf(stderr, "PR_Delete failed\n");
+ exit(1);
+ }
+}
+
+int main(int argc, char **argv)
+{
+ PRFileDesc *listenSock;
+ PRThread *clientThread;
+ PRThread *serverThread;
+ PRNetAddr addr;
+ PRThreadScope scope = PR_GLOBAL_THREAD;
+
+ listenSock = PR_NewTCPSocket();
+ if (NULL == listenSock) {
+ fprintf(stderr, "PR_NewTCPSocket failed\n");
+ exit(1);
+ }
+ if (PR_InitializeNetAddr(PR_IpAddrAny, 0, &addr) == PR_FAILURE) {
+ fprintf(stderr, "PR_InitializeNetAddr failed\n");
+ exit(1);
+ }
+ if (PR_Bind(listenSock, &addr) == PR_FAILURE) {
+ fprintf(stderr, "PR_Bind failed\n");
+ exit(1);
+ }
+ /* Find out what port number we are bound to. */
+ if (PR_GetSockName(listenSock, &addr) == PR_FAILURE) {
+ fprintf(stderr, "PR_GetSockName failed\n");
+ exit(1);
+ }
+ if (PR_Listen(listenSock, 5) == PR_FAILURE) {
+ fprintf(stderr, "PR_Listen failed\n");
+ exit(1);
+ }
+
+ clientThread = PR_CreateThread(PR_USER_THREAD,
+ ClientThread, (void *) PR_ntohs(PR_NetAddrInetPort(&addr)),
+ PR_PRIORITY_NORMAL, scope, PR_JOINABLE_THREAD, 0);
+ if (NULL == clientThread) {
+ fprintf(stderr, "PR_CreateThread failed\n");
+ exit(1);
+ }
+ serverThread = PR_CreateThread(PR_USER_THREAD,
+ ServerThread, listenSock,
+ PR_PRIORITY_NORMAL, scope, PR_JOINABLE_THREAD, 0);
+ if (NULL == serverThread) {
+ fprintf(stderr, "PR_CreateThread failed\n");
+ exit(1);
+ }
+ if (PR_JoinThread(clientThread) == PR_FAILURE) {
+ fprintf(stderr, "PR_JoinThread failed\n");
+ exit(1);
+ }
+ if (PR_JoinThread(serverThread) == PR_FAILURE) {
+ fprintf(stderr, "PR_JoinThread failed\n");
+ exit(1);
+ }
+ if (PR_Close(listenSock) == PR_FAILURE) {
+ fprintf(stderr, "PR_Close failed\n");
+ exit(1);
+ }
+ printf("PASS\n");
+ return 0;
+}
diff --git a/nsprpub/pr/tests/server_test.c b/nsprpub/pr/tests/server_test.c
new file mode 100644
index 0000000000..93ffe4aff2
--- /dev/null
+++ b/nsprpub/pr/tests/server_test.c
@@ -0,0 +1,692 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/***********************************************************************
+**
+** This server simulates a server running in loopback mode.
+**
+** The idea is that a single server is created. The server initially creates
+** a number of worker threads. Then, with the server running, a number of
+** clients are created which start requesting service from the server.
+**
+**
+** Modification History:
+** 19-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
+** The debug mode will print all of the printfs associated with this test.
+** The regress mode will be the default mode. Since the regress tool limits
+** the output to a one line status:PASS or FAIL,all of the printf statements
+** have been handled with an if (debug_mode) statement.
+***********************************************************************/
+
+/***********************************************************************
+** Includes
+***********************************************************************/
+/* Used to get the command line option */
+#include "plgetopt.h"
+
+#include "nspr.h"
+#include "pprthred.h"
+
+#include <string.h>
+
+#define PORT 15004
+#define THREAD_STACKSIZE 0
+
+#define PASS 0
+#define FAIL 1
+static int debug_mode = 0;
+static int failed_already = 0;
+
+static int _iterations = 1000;
+static int _clients = 1;
+static int _client_data = 250;
+static int _server_data = (8*1024);
+
+static PRThreadScope ServerScope, ClientScope;
+
+#define SERVER "Server"
+#define MAIN "Main"
+
+#define SERVER_STATE_STARTUP 0
+#define SERVER_STATE_READY 1
+#define SERVER_STATE_DYING 2
+#define SERVER_STATE_DEAD 4
+int ServerState;
+PRLock *ServerStateCVLock;
+PRCondVar *ServerStateCV;
+
+#undef DEBUGPRINTS
+#ifdef DEBUGPRINTS
+#define DPRINTF printf
+#else
+#define DPRINTF
+#endif
+
+
+/***********************************************************************
+** PRIVATE FUNCTION: Test_Result
+** DESCRIPTION: Used in conjunction with the regress tool, prints out the
+** status of the test case.
+** INPUTS: PASS/FAIL
+** OUTPUTS: None
+** RETURN: None
+** SIDE EFFECTS:
+**
+** RESTRICTIONS:
+** None
+** MEMORY: NA
+** ALGORITHM: Determine what the status is and print accordingly.
+**
+***********************************************************************/
+
+
+static void Test_Result (int result)
+{
+ switch (result)
+ {
+ case PASS:
+ printf ("PASS\n");
+ break;
+ case FAIL:
+ printf ("FAIL\n");
+ failed_already = 1;
+ break;
+ default:
+ break;
+ }
+}
+
+static void do_work(void);
+
+/* --- Server state functions --------------------------------------------- */
+void
+SetServerState(char *waiter, PRInt32 state)
+{
+ PR_Lock(ServerStateCVLock);
+ ServerState = state;
+ PR_NotifyCondVar(ServerStateCV);
+
+ if (debug_mode) {
+ DPRINTF("\t%s changed state to %d\n", waiter, state);
+ }
+
+ PR_Unlock(ServerStateCVLock);
+}
+
+int
+WaitServerState(char *waiter, PRInt32 state)
+{
+ PRInt32 rv;
+
+ PR_Lock(ServerStateCVLock);
+
+ if (debug_mode) {
+ DPRINTF("\t%s waiting for state %d\n", waiter, state);
+ }
+
+ while(!(ServerState & state)) {
+ PR_WaitCondVar(ServerStateCV, PR_INTERVAL_NO_TIMEOUT);
+ }
+ rv = ServerState;
+
+ if (debug_mode) DPRINTF("\t%s resuming from wait for state %d; state now %d\n",
+ waiter, state, ServerState);
+ PR_Unlock(ServerStateCVLock);
+
+ return rv;
+}
+
+/* --- Server Functions ------------------------------------------- */
+
+PRLock *workerThreadsLock;
+PRInt32 workerThreads;
+PRInt32 workerThreadsBusy;
+
+void
+WorkerThreadFunc(void *_listenSock)
+{
+ PRFileDesc *listenSock = (PRFileDesc *)_listenSock;
+ PRInt32 bytesRead;
+ PRInt32 bytesWritten;
+ char *dataBuf;
+ char *sendBuf;
+
+ if (debug_mode) DPRINTF("\tServer buffer is %d bytes; %d data, %d netaddrs\n",
+ _client_data+(2*sizeof(PRNetAddr))+32, _client_data, (2*sizeof(PRNetAddr))+32);
+ dataBuf = (char *)PR_MALLOC(_client_data + 2*sizeof(PRNetAddr) + 32);
+ if (!dataBuf)
+ if (debug_mode) {
+ printf("\tServer could not malloc space!?\n");
+ }
+ sendBuf = (char *)PR_MALLOC(_server_data *sizeof(char));
+ if (!sendBuf)
+ if (debug_mode) {
+ printf("\tServer could not malloc space!?\n");
+ }
+
+ if (debug_mode) {
+ DPRINTF("\tServer worker thread running\n");
+ }
+
+ while(1) {
+ PRInt32 bytesToRead = _client_data;
+ PRInt32 bytesToWrite = _server_data;
+ PRFileDesc *newSock;
+ PRNetAddr *rAddr;
+ PRInt32 loops = 0;
+
+ loops++;
+
+ if (debug_mode) {
+ DPRINTF("\tServer thread going into accept\n");
+ }
+
+ bytesRead = PR_AcceptRead(listenSock,
+ &newSock,
+ &rAddr,
+ dataBuf,
+ bytesToRead,
+ PR_INTERVAL_NO_TIMEOUT);
+
+ if (bytesRead < 0) {
+ if (debug_mode) {
+ printf("\tServer error in accept (%d)\n", bytesRead);
+ }
+ continue;
+ }
+
+ if (debug_mode) {
+ DPRINTF("\tServer accepted connection (%d bytes)\n", bytesRead);
+ }
+
+ PR_AtomicIncrement(&workerThreadsBusy);
+ if (workerThreadsBusy == workerThreads) {
+ PR_Lock(workerThreadsLock);
+ if (workerThreadsBusy == workerThreads) {
+ PRThread *WorkerThread;
+
+ WorkerThread = PR_CreateThread(
+ PR_SYSTEM_THREAD,
+ WorkerThreadFunc,
+ listenSock,
+ PR_PRIORITY_NORMAL,
+ ServerScope,
+ PR_UNJOINABLE_THREAD,
+ THREAD_STACKSIZE);
+
+ if (!WorkerThread) {
+ if (debug_mode) {
+ printf("Error creating client thread %d\n", workerThreads);
+ }
+ } else {
+ PR_AtomicIncrement(&workerThreads);
+ if (debug_mode) {
+ DPRINTF("\tServer creates worker (%d)\n", workerThreads);
+ }
+ }
+ }
+ PR_Unlock(workerThreadsLock);
+ }
+
+ bytesToRead -= bytesRead;
+ while (bytesToRead) {
+ bytesRead = PR_Recv(newSock,
+ dataBuf,
+ bytesToRead,
+ 0,
+ PR_INTERVAL_NO_TIMEOUT);
+ if (bytesRead < 0) {
+ if (debug_mode) {
+ printf("\tServer error receiving data (%d)\n", bytesRead);
+ }
+ continue;
+ }
+ if (debug_mode) {
+ DPRINTF("\tServer received %d bytes\n", bytesRead);
+ }
+ }
+
+ bytesWritten = PR_Send(newSock,
+ sendBuf,
+ bytesToWrite,
+ 0,
+ PR_INTERVAL_NO_TIMEOUT);
+ if (bytesWritten != _server_data) {
+ if (debug_mode) printf("\tError sending data to client (%d, %d)\n",
+ bytesWritten, PR_GetOSError());
+ } else {
+ if (debug_mode) {
+ DPRINTF("\tServer sent %d bytes\n", bytesWritten);
+ }
+ }
+
+ PR_Close(newSock);
+ PR_AtomicDecrement(&workerThreadsBusy);
+ }
+}
+
+PRFileDesc *
+ServerSetup(void)
+{
+ PRFileDesc *listenSocket;
+ PRSocketOptionData sockOpt;
+ PRNetAddr serverAddr;
+ PRThread *WorkerThread;
+
+ if ((listenSocket = PR_NewTCPSocket()) == NULL) {
+ if (debug_mode) {
+ printf("\tServer error creating listen socket\n");
+ }
+ else {
+ Test_Result(FAIL);
+ }
+ return NULL;
+ }
+
+ sockOpt.option = PR_SockOpt_Reuseaddr;
+ sockOpt.value.reuse_addr = PR_TRUE;
+ if (PR_SetSocketOption(listenSocket, &sockOpt) != PR_SUCCESS) {
+ if (debug_mode) printf("\tServer error setting socket option: OS error %d\n",
+ PR_GetOSError());
+ else {
+ Test_Result(FAIL);
+ }
+ PR_Close(listenSocket);
+ return NULL;
+ }
+
+ memset(&serverAddr, 0, sizeof(PRNetAddr));
+ serverAddr.inet.family = PR_AF_INET;
+ serverAddr.inet.port = PR_htons(PORT);
+ serverAddr.inet.ip = PR_htonl(PR_INADDR_ANY);
+
+ if (PR_Bind(listenSocket, &serverAddr) != PR_SUCCESS) {
+ if (debug_mode) printf("\tServer error binding to server address: OS error %d\n",
+ PR_GetOSError());
+ else {
+ Test_Result(FAIL);
+ }
+ PR_Close(listenSocket);
+ return NULL;
+ }
+
+ if (PR_Listen(listenSocket, 128) != PR_SUCCESS) {
+ if (debug_mode) {
+ printf("\tServer error listening to server socket\n");
+ }
+ else {
+ Test_Result(FAIL);
+ }
+ PR_Close(listenSocket);
+
+ return NULL;
+ }
+
+ /* Create Clients */
+ workerThreads = 0;
+ workerThreadsBusy = 0;
+
+ workerThreadsLock = PR_NewLock();
+
+ WorkerThread = PR_CreateThread(
+ PR_SYSTEM_THREAD,
+ WorkerThreadFunc,
+ listenSocket,
+ PR_PRIORITY_NORMAL,
+ ServerScope,
+ PR_UNJOINABLE_THREAD,
+ THREAD_STACKSIZE);
+
+ if (!WorkerThread) {
+ if (debug_mode) {
+ printf("error creating working thread\n");
+ }
+ PR_Close(listenSocket);
+ return NULL;
+ }
+ PR_AtomicIncrement(&workerThreads);
+ if (debug_mode) {
+ DPRINTF("\tServer created primordial worker thread\n");
+ }
+
+ return listenSocket;
+}
+
+/* The main server loop */
+void
+ServerThreadFunc(void *unused)
+{
+ PRFileDesc *listenSocket;
+
+ /* Do setup */
+ listenSocket = ServerSetup();
+
+ if (!listenSocket) {
+ SetServerState(SERVER, SERVER_STATE_DEAD);
+ } else {
+
+ if (debug_mode) {
+ DPRINTF("\tServer up\n");
+ }
+
+ /* Tell clients they can start now. */
+ SetServerState(SERVER, SERVER_STATE_READY);
+
+ /* Now wait for server death signal */
+ WaitServerState(SERVER, SERVER_STATE_DYING);
+
+ /* Cleanup */
+ SetServerState(SERVER, SERVER_STATE_DEAD);
+ }
+}
+
+/* --- Client Functions ------------------------------------------- */
+
+PRInt32 numRequests;
+PRInt32 numClients;
+PRMonitor *clientMonitor;
+
+void
+ClientThreadFunc(void *unused)
+{
+ PRNetAddr serverAddr;
+ PRFileDesc *clientSocket;
+ char *sendBuf;
+ char *recvBuf;
+ PRInt32 rv;
+ PRInt32 bytesNeeded;
+
+ sendBuf = (char *)PR_MALLOC(_client_data * sizeof(char));
+ if (!sendBuf)
+ if (debug_mode) {
+ printf("\tClient could not malloc space!?\n");
+ }
+ recvBuf = (char *)PR_MALLOC(_server_data * sizeof(char));
+ if (!recvBuf)
+ if (debug_mode) {
+ printf("\tClient could not malloc space!?\n");
+ }
+
+ memset(&serverAddr, 0, sizeof(PRNetAddr));
+ serverAddr.inet.family = PR_AF_INET;
+ serverAddr.inet.port = PR_htons(PORT);
+ serverAddr.inet.ip = PR_htonl(PR_INADDR_LOOPBACK);
+
+ while(numRequests > 0) {
+
+ if ( (numRequests % 10) == 0 )
+ if (debug_mode) {
+ printf(".");
+ }
+ if (debug_mode) {
+ DPRINTF("\tClient starting request %d\n", numRequests);
+ }
+
+ clientSocket = PR_NewTCPSocket();
+ if (!clientSocket) {
+ if (debug_mode) printf("Client error creating socket: OS error %d\n",
+ PR_GetOSError());
+ continue;
+ }
+
+ if (debug_mode) {
+ DPRINTF("\tClient connecting\n");
+ }
+
+ rv = PR_Connect(clientSocket,
+ &serverAddr,
+ PR_INTERVAL_NO_TIMEOUT);
+ if (!clientSocket) {
+ if (debug_mode) {
+ printf("\tClient error connecting\n");
+ }
+ continue;
+ }
+
+ if (debug_mode) {
+ DPRINTF("\tClient connected\n");
+ }
+
+ rv = PR_Send(clientSocket,
+ sendBuf,
+ _client_data,
+ 0,
+ PR_INTERVAL_NO_TIMEOUT);
+ if (rv != _client_data) {
+ if (debug_mode) {
+ printf("Client error sending data (%d)\n", rv);
+ }
+ PR_Close(clientSocket);
+ continue;
+ }
+
+ if (debug_mode) {
+ DPRINTF("\tClient sent %d bytes\n", rv);
+ }
+
+ bytesNeeded = _server_data;
+ while(bytesNeeded) {
+ rv = PR_Recv(clientSocket,
+ recvBuf,
+ bytesNeeded,
+ 0,
+ PR_INTERVAL_NO_TIMEOUT);
+ if (rv <= 0) {
+ if (debug_mode) printf("Client error receiving data (%d) (%d/%d)\n",
+ rv, (_server_data - bytesNeeded), _server_data);
+ break;
+ }
+ if (debug_mode) {
+ DPRINTF("\tClient received %d bytes; need %d more\n", rv, bytesNeeded - rv);
+ }
+ bytesNeeded -= rv;
+ }
+
+ PR_Close(clientSocket);
+
+ PR_AtomicDecrement(&numRequests);
+ }
+
+ PR_EnterMonitor(clientMonitor);
+ --numClients;
+ PR_Notify(clientMonitor);
+ PR_ExitMonitor(clientMonitor);
+
+ PR_DELETE(sendBuf);
+ PR_DELETE(recvBuf);
+}
+
+void
+RunClients(void)
+{
+ PRInt32 index;
+
+ numRequests = _iterations;
+ numClients = _clients;
+ clientMonitor = PR_NewMonitor();
+
+ for (index=0; index<_clients; index++) {
+ PRThread *clientThread;
+
+
+ clientThread = PR_CreateThread(
+ PR_USER_THREAD,
+ ClientThreadFunc,
+ NULL,
+ PR_PRIORITY_NORMAL,
+ ClientScope,
+ PR_UNJOINABLE_THREAD,
+ THREAD_STACKSIZE);
+
+ if (!clientThread) {
+ if (debug_mode) {
+ printf("\terror creating client thread %d\n", index);
+ }
+ } else if (debug_mode) {
+ DPRINTF("\tMain created client %d/%d\n", index+1, _clients);
+ }
+
+ }
+
+ PR_EnterMonitor(clientMonitor);
+ while(numClients) {
+ PR_Wait(clientMonitor, PR_INTERVAL_NO_TIMEOUT);
+ }
+ PR_ExitMonitor(clientMonitor);
+}
+
+/* --- Main Function ---------------------------------------------- */
+
+static
+void do_work()
+{
+ PRThread *ServerThread;
+ PRInt32 state;
+
+ SetServerState(MAIN, SERVER_STATE_STARTUP);
+ ServerThread = PR_CreateThread(
+ PR_USER_THREAD,
+ ServerThreadFunc,
+ NULL,
+ PR_PRIORITY_NORMAL,
+ ServerScope,
+ PR_JOINABLE_THREAD,
+ THREAD_STACKSIZE);
+ if (!ServerThread) {
+ if (debug_mode) {
+ printf("error creating main server thread\n");
+ }
+ return;
+ }
+
+ /* Wait for server to be ready */
+ state = WaitServerState(MAIN, SERVER_STATE_READY|SERVER_STATE_DEAD);
+
+ if (!(state & SERVER_STATE_DEAD)) {
+ /* Run Test Clients */
+ RunClients();
+
+ /* Send death signal to server */
+ SetServerState(MAIN, SERVER_STATE_DYING);
+ }
+
+ PR_JoinThread(ServerThread);
+}
+
+static void do_workUU(void)
+{
+ ServerScope = PR_LOCAL_THREAD;
+ ClientScope = PR_LOCAL_THREAD;
+ do_work();
+}
+
+static void do_workUK(void)
+{
+ ServerScope = PR_LOCAL_THREAD;
+ ClientScope = PR_GLOBAL_THREAD;
+ do_work();
+}
+
+static void do_workKU(void)
+{
+ ServerScope = PR_GLOBAL_THREAD;
+ ClientScope = PR_LOCAL_THREAD;
+ do_work();
+}
+
+static void do_workKK(void)
+{
+ ServerScope = PR_GLOBAL_THREAD;
+ ClientScope = PR_GLOBAL_THREAD;
+ do_work();
+}
+
+
+static void Measure(void (*func)(void), const char *msg)
+{
+ PRIntervalTime start, stop;
+ double d;
+
+ start = PR_IntervalNow();
+ (*func)();
+ stop = PR_IntervalNow();
+
+ d = (double)PR_IntervalToMicroseconds(stop - start);
+
+ if (debug_mode) {
+ printf("\n%40s: %6.2f usec\n", msg, d / _iterations);
+ }
+}
+
+
+int main(int argc, char **argv)
+{
+ /* The command line argument: -d is used to determine if the test is being run
+ in debug mode. The regress tool requires only one line output:PASS or FAIL.
+ All of the printfs associated with this test has been handled with a if (debug_mode)
+ test.
+ Usage: test_name -d
+ */
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "d");
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 'd': /* debug mode */
+ debug_mode = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ /* main test */
+ if (debug_mode) {
+ printf("Enter number of iterations: \n");
+ scanf("%d", &_iterations);
+ printf("Enter number of clients : \n");
+ scanf("%d", &_clients);
+ printf("Enter size of client data : \n");
+ scanf("%d", &_client_data);
+ printf("Enter size of server data : \n");
+ scanf("%d", &_server_data);
+ }
+ else
+ {
+
+ _iterations = 10;
+ _clients = 1;
+ _client_data = 10;
+ _server_data = 10;
+ }
+
+ if (debug_mode) {
+ printf("\n\n%d iterations with %d client threads.\n",
+ _iterations, _clients);
+ printf("Sending %d bytes of client data and %d bytes of server data\n",
+ _client_data, _server_data);
+ }
+ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
+ PR_STDIO_INIT();
+
+ ServerStateCVLock = PR_NewLock();
+ ServerStateCV = PR_NewCondVar(ServerStateCVLock);
+
+ Measure(do_workUU, "server loop user/user");
+#if 0
+ Measure(do_workUK, "server loop user/kernel");
+ Measure(do_workKU, "server loop kernel/user");
+ Measure(do_workKK, "server loop kernel/kernel");
+#endif
+
+ PR_Cleanup();
+
+ return failed_already;
+}
diff --git a/nsprpub/pr/tests/servr_kk.c b/nsprpub/pr/tests/servr_kk.c
new file mode 100644
index 0000000000..06f4fae117
--- /dev/null
+++ b/nsprpub/pr/tests/servr_kk.c
@@ -0,0 +1,659 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/***********************************************************************
+**
+** This server simulates a server running in loopback mode.
+**
+** The idea is that a single server is created. The server initially creates
+** a number of worker threads. Then, with the server running, a number of
+** clients are created which start requesting service from the server.
+**
+**
+** Modification History:
+** 19-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
+** The debug mode will print all of the printfs associated with this test.
+** The regress mode will be the default mode. Since the regress tool limits
+** the output to a one line status:PASS or FAIL,all of the printf statements
+** have been handled with an if (debug_mode) statement.
+** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to
+** recognize the return code from tha main program.
+***********************************************************************/
+
+/***********************************************************************
+** Includes
+***********************************************************************/
+/* Used to get the command line option */
+#include "plgetopt.h"
+
+#include "nspr.h"
+#include "pprthred.h"
+
+#include <string.h>
+
+#define PORT 15004
+#define THREAD_STACKSIZE 0
+
+static int _iterations = 1000;
+static int _clients = 1;
+static int _client_data = 250;
+static int _server_data = (8*1024);
+
+static PRThreadScope ServerScope, ClientScope;
+
+#define SERVER "Server"
+#define MAIN "Main"
+
+#define SERVER_STATE_STARTUP 0
+#define SERVER_STATE_READY 1
+#define SERVER_STATE_DYING 2
+#define SERVER_STATE_DEAD 4
+int ServerState;
+PRLock *ServerStateCVLock;
+PRCondVar *ServerStateCV;
+
+#ifdef DEBUGPRINTS
+#define DPRINTF printf
+#else
+#define DPRINTF
+#endif
+
+PRIntn failed_already=0;
+PRIntn debug_mode;
+static void do_work(void);
+
+/* --- Server state functions --------------------------------------------- */
+void
+SetServerState(char *waiter, PRInt32 state)
+{
+ PR_Lock(ServerStateCVLock);
+ ServerState = state;
+ PR_NotifyCondVar(ServerStateCV);
+
+ if (debug_mode) {
+ DPRINTF("\t%s changed state to %d\n", waiter, state);
+ }
+
+ PR_Unlock(ServerStateCVLock);
+}
+
+int
+WaitServerState(char *waiter, PRInt32 state)
+{
+ PRInt32 rv;
+
+ PR_Lock(ServerStateCVLock);
+
+ if (debug_mode) {
+ DPRINTF("\t%s waiting for state %d\n", waiter, state);
+ }
+
+ while(!(ServerState & state)) {
+ PR_WaitCondVar(ServerStateCV, PR_INTERVAL_NO_TIMEOUT);
+ }
+ rv = ServerState;
+
+ if (debug_mode) DPRINTF("\t%s resuming from wait for state %d; state now %d\n",
+ waiter, state, ServerState);
+ PR_Unlock(ServerStateCVLock);
+
+ return rv;
+}
+
+/* --- Server Functions ------------------------------------------- */
+
+PRLock *workerThreadsLock;
+PRInt32 workerThreads;
+PRInt32 workerThreadsBusy;
+
+void
+WorkerThreadFunc(void *_listenSock)
+{
+ PRFileDesc *listenSock = (PRFileDesc *)_listenSock;
+ PRInt32 bytesRead;
+ PRInt32 bytesWritten;
+ char *dataBuf;
+ char *sendBuf;
+
+ if (debug_mode) DPRINTF("\tServer buffer is %d bytes; %d data, %d netaddrs\n",
+ _client_data+(2*sizeof(PRNetAddr))+32, _client_data, (2*sizeof(PRNetAddr))+32);
+ dataBuf = (char *)PR_MALLOC(_client_data + 2*sizeof(PRNetAddr) + 32);
+ if (!dataBuf)
+ if (debug_mode) {
+ printf("\tServer could not malloc space!?\n");
+ }
+ sendBuf = (char *)PR_MALLOC(_server_data *sizeof(char));
+ if (!sendBuf)
+ if (debug_mode) {
+ printf("\tServer could not malloc space!?\n");
+ }
+
+ if (debug_mode) {
+ DPRINTF("\tServer worker thread running\n");
+ }
+
+ while(1) {
+ PRInt32 bytesToRead = _client_data;
+ PRInt32 bytesToWrite = _server_data;
+ PRFileDesc *newSock;
+ PRNetAddr *rAddr;
+ PRInt32 loops = 0;
+
+ loops++;
+
+ if (debug_mode) {
+ DPRINTF("\tServer thread going into accept\n");
+ }
+
+ bytesRead = PR_AcceptRead(listenSock,
+ &newSock,
+ &rAddr,
+ dataBuf,
+ bytesToRead,
+ PR_INTERVAL_NO_TIMEOUT);
+
+ if (bytesRead < 0) {
+ if (debug_mode) {
+ printf("\tServer error in accept (%d)\n", bytesRead);
+ }
+ continue;
+ }
+
+ if (debug_mode) {
+ DPRINTF("\tServer accepted connection (%d bytes)\n", bytesRead);
+ }
+
+ PR_AtomicIncrement(&workerThreadsBusy);
+ if (workerThreadsBusy == workerThreads) {
+ PR_Lock(workerThreadsLock);
+ if (workerThreadsBusy == workerThreads) {
+ PRThread *WorkerThread;
+
+ WorkerThread = PR_CreateThread(
+ PR_SYSTEM_THREAD,
+ WorkerThreadFunc,
+ listenSock,
+ PR_PRIORITY_NORMAL,
+ ServerScope,
+ PR_UNJOINABLE_THREAD,
+ THREAD_STACKSIZE);
+
+ if (!WorkerThread) {
+ if (debug_mode) {
+ printf("Error creating client thread %d\n", workerThreads);
+ }
+ } else {
+ PR_AtomicIncrement(&workerThreads);
+ if (debug_mode) {
+ DPRINTF("\tServer creates worker (%d)\n", workerThreads);
+ }
+ }
+ }
+ PR_Unlock(workerThreadsLock);
+ }
+
+ bytesToRead -= bytesRead;
+ while (bytesToRead) {
+ bytesRead = PR_Recv(newSock,
+ dataBuf,
+ bytesToRead,
+ 0,
+ PR_INTERVAL_NO_TIMEOUT);
+ if (bytesRead < 0) {
+ if (debug_mode) {
+ printf("\tServer error receiving data (%d)\n", bytesRead);
+ }
+ continue;
+ }
+ if (debug_mode) {
+ DPRINTF("\tServer received %d bytes\n", bytesRead);
+ }
+ }
+
+ bytesWritten = PR_Send(newSock,
+ sendBuf,
+ bytesToWrite,
+ 0,
+ PR_INTERVAL_NO_TIMEOUT);
+ if (bytesWritten != _server_data) {
+ if (debug_mode) printf("\tError sending data to client (%d, %d)\n",
+ bytesWritten, PR_GetOSError());
+ } else {
+ if (debug_mode) {
+ DPRINTF("\tServer sent %d bytes\n", bytesWritten);
+ }
+ }
+
+ PR_Close(newSock);
+ PR_AtomicDecrement(&workerThreadsBusy);
+ }
+}
+
+PRFileDesc *
+ServerSetup(void)
+{
+ PRFileDesc *listenSocket;
+ PRSocketOptionData sockOpt;
+ PRNetAddr serverAddr;
+ PRThread *WorkerThread;
+
+ if ( (listenSocket = PR_NewTCPSocket()) == NULL) {
+ if (debug_mode) {
+ printf("\tServer error creating listen socket\n");
+ }
+ else {
+ failed_already=1;
+ }
+ return NULL;
+ }
+
+ sockOpt.option = PR_SockOpt_Reuseaddr;
+ sockOpt.value.reuse_addr = PR_TRUE;
+ if ( PR_SetSocketOption(listenSocket, &sockOpt) == PR_FAILURE) {
+ if (debug_mode) printf("\tServer error setting socket option: OS error %d\n",
+ PR_GetOSError());
+ else {
+ failed_already=1;
+ }
+ PR_Close(listenSocket);
+ return NULL;
+ }
+
+ memset(&serverAddr, 0, sizeof(PRNetAddr));
+ serverAddr.inet.family = PR_AF_INET;
+ serverAddr.inet.port = PR_htons(PORT);
+ serverAddr.inet.ip = PR_htonl(PR_INADDR_ANY);
+
+ if ( PR_Bind(listenSocket, &serverAddr) == PR_FAILURE) {
+ if (debug_mode) printf("\tServer error binding to server address: OS error %d\n",
+ PR_GetOSError());
+ else {
+ failed_already=1;
+ }
+ PR_Close(listenSocket);
+ return NULL;
+ }
+
+ if ( PR_Listen(listenSocket, 128) == PR_FAILURE) {
+ if (debug_mode) {
+ printf("\tServer error listening to server socket\n");
+ }
+ else {
+ failed_already=1;
+ }
+ PR_Close(listenSocket);
+
+ return NULL;
+ }
+
+ /* Create Clients */
+ workerThreads = 0;
+ workerThreadsBusy = 0;
+
+ workerThreadsLock = PR_NewLock();
+
+ WorkerThread = PR_CreateThread(
+ PR_SYSTEM_THREAD,
+ WorkerThreadFunc,
+ listenSocket,
+ PR_PRIORITY_NORMAL,
+ ServerScope,
+ PR_UNJOINABLE_THREAD,
+ THREAD_STACKSIZE);
+
+ if (!WorkerThread) {
+ if (debug_mode) {
+ printf("error creating working thread\n");
+ }
+ PR_Close(listenSocket);
+ return NULL;
+ }
+ PR_AtomicIncrement(&workerThreads);
+ if (debug_mode) {
+ DPRINTF("\tServer created primordial worker thread\n");
+ }
+
+ return listenSocket;
+}
+
+/* The main server loop */
+void
+ServerThreadFunc(void *unused)
+{
+ PRFileDesc *listenSocket;
+
+ /* Do setup */
+ listenSocket = ServerSetup();
+
+ if (!listenSocket) {
+ SetServerState(SERVER, SERVER_STATE_DEAD);
+ } else {
+
+ if (debug_mode) {
+ DPRINTF("\tServer up\n");
+ }
+
+ /* Tell clients they can start now. */
+ SetServerState(SERVER, SERVER_STATE_READY);
+
+ /* Now wait for server death signal */
+ WaitServerState(SERVER, SERVER_STATE_DYING);
+
+ /* Cleanup */
+ SetServerState(SERVER, SERVER_STATE_DEAD);
+ }
+}
+
+/* --- Client Functions ------------------------------------------- */
+
+PRInt32 numRequests;
+PRInt32 numClients;
+PRMonitor *clientMonitor;
+
+void
+ClientThreadFunc(void *unused)
+{
+ PRNetAddr serverAddr;
+ PRFileDesc *clientSocket;
+ char *sendBuf;
+ char *recvBuf;
+ PRInt32 rv;
+ PRInt32 bytesNeeded;
+
+ sendBuf = (char *)PR_MALLOC(_client_data * sizeof(char));
+ if (!sendBuf)
+ if (debug_mode) {
+ printf("\tClient could not malloc space!?\n");
+ }
+ recvBuf = (char *)PR_MALLOC(_server_data * sizeof(char));
+ if (!recvBuf)
+ if (debug_mode) {
+ printf("\tClient could not malloc space!?\n");
+ }
+
+ memset(&serverAddr, 0, sizeof(PRNetAddr));
+ serverAddr.inet.family = PR_AF_INET;
+ serverAddr.inet.port = PR_htons(PORT);
+ serverAddr.inet.ip = PR_htonl(PR_INADDR_LOOPBACK);
+
+ while(numRequests > 0) {
+
+ if ( (numRequests % 10) == 0 )
+ if (debug_mode) {
+ printf(".");
+ }
+ if (debug_mode) {
+ DPRINTF("\tClient starting request %d\n", numRequests);
+ }
+
+ clientSocket = PR_NewTCPSocket();
+ if (!clientSocket) {
+ if (debug_mode) printf("Client error creating socket: OS error %d\n",
+ PR_GetOSError());
+ continue;
+ }
+
+ if (debug_mode) {
+ DPRINTF("\tClient connecting\n");
+ }
+
+ rv = PR_Connect(clientSocket,
+ &serverAddr,
+ PR_INTERVAL_NO_TIMEOUT);
+ if (!clientSocket) {
+ if (debug_mode) {
+ printf("\tClient error connecting\n");
+ }
+ continue;
+ }
+
+ if (debug_mode) {
+ DPRINTF("\tClient connected\n");
+ }
+
+ rv = PR_Send(clientSocket,
+ sendBuf,
+ _client_data,
+ 0,
+ PR_INTERVAL_NO_TIMEOUT);
+ if (rv != _client_data) {
+ if (debug_mode) {
+ printf("Client error sending data (%d)\n", rv);
+ }
+ PR_Close(clientSocket);
+ continue;
+ }
+
+ if (debug_mode) {
+ DPRINTF("\tClient sent %d bytes\n", rv);
+ }
+
+ bytesNeeded = _server_data;
+ while(bytesNeeded) {
+ rv = PR_Recv(clientSocket,
+ recvBuf,
+ bytesNeeded,
+ 0,
+ PR_INTERVAL_NO_TIMEOUT);
+ if (rv <= 0) {
+ if (debug_mode) printf("Client error receiving data (%d) (%d/%d)\n",
+ rv, (_server_data - bytesNeeded), _server_data);
+ break;
+ }
+ if (debug_mode) {
+ DPRINTF("\tClient received %d bytes; need %d more\n", rv, bytesNeeded - rv);
+ }
+ bytesNeeded -= rv;
+ }
+
+ PR_Close(clientSocket);
+
+ PR_AtomicDecrement(&numRequests);
+ }
+
+ PR_EnterMonitor(clientMonitor);
+ --numClients;
+ PR_Notify(clientMonitor);
+ PR_ExitMonitor(clientMonitor);
+
+ PR_DELETE(sendBuf);
+ PR_DELETE(recvBuf);
+}
+
+void
+RunClients(void)
+{
+ PRInt32 index;
+
+ numRequests = _iterations;
+ numClients = _clients;
+ clientMonitor = PR_NewMonitor();
+
+ for (index=0; index<_clients; index++) {
+ PRThread *clientThread;
+
+
+ clientThread = PR_CreateThread(
+ PR_USER_THREAD,
+ ClientThreadFunc,
+ NULL,
+ PR_PRIORITY_NORMAL,
+ ClientScope,
+ PR_UNJOINABLE_THREAD,
+ THREAD_STACKSIZE);
+
+ if (!clientThread) {
+ if (debug_mode) {
+ printf("\terror creating client thread %d\n", index);
+ }
+ } else if (debug_mode) {
+ DPRINTF("\tMain created client %d/%d\n", index+1, _clients);
+ }
+
+ }
+
+ PR_EnterMonitor(clientMonitor);
+ while(numClients) {
+ PR_Wait(clientMonitor, PR_INTERVAL_NO_TIMEOUT);
+ }
+ PR_ExitMonitor(clientMonitor);
+}
+
+/* --- Main Function ---------------------------------------------- */
+
+static
+void do_work()
+{
+ PRThread *ServerThread;
+ PRInt32 state;
+
+ SetServerState(MAIN, SERVER_STATE_STARTUP);
+ ServerThread = PR_CreateThread(
+ PR_USER_THREAD,
+ ServerThreadFunc,
+ NULL,
+ PR_PRIORITY_NORMAL,
+ ServerScope,
+ PR_JOINABLE_THREAD,
+ THREAD_STACKSIZE);
+ if (!ServerThread) {
+ if (debug_mode) {
+ printf("error creating main server thread\n");
+ }
+ return;
+ }
+
+ /* Wait for server to be ready */
+ state = WaitServerState(MAIN, SERVER_STATE_READY|SERVER_STATE_DEAD);
+
+ if (!(state & SERVER_STATE_DEAD)) {
+ /* Run Test Clients */
+ RunClients();
+
+ /* Send death signal to server */
+ SetServerState(MAIN, SERVER_STATE_DYING);
+ }
+
+ PR_JoinThread(ServerThread);
+}
+
+static void do_workUU(void)
+{
+ ServerScope = PR_LOCAL_THREAD;
+ ClientScope = PR_LOCAL_THREAD;
+ do_work();
+}
+
+static void do_workUK(void)
+{
+ ServerScope = PR_LOCAL_THREAD;
+ ClientScope = PR_GLOBAL_THREAD;
+ do_work();
+}
+
+static void do_workKU(void)
+{
+ ServerScope = PR_GLOBAL_THREAD;
+ ClientScope = PR_LOCAL_THREAD;
+ do_work();
+}
+
+static void do_workKK(void)
+{
+ ServerScope = PR_GLOBAL_THREAD;
+ ClientScope = PR_GLOBAL_THREAD;
+ do_work();
+}
+
+
+static void Measure(void (*func)(void), const char *msg)
+{
+ PRIntervalTime start, stop;
+ double d;
+
+ start = PR_IntervalNow();
+ (*func)();
+ stop = PR_IntervalNow();
+
+ d = (double)PR_IntervalToMicroseconds(stop - start);
+
+ if (debug_mode) {
+ printf("\n%40s: %6.2f usec\n", msg, d / _iterations);
+ }
+}
+
+
+int main(int argc, char **argv)
+{
+ /* The command line argument: -d is used to determine if the test is being run
+ in debug mode. The regress tool requires only one line output:PASS or FAIL.
+ All of the printfs associated with this test has been handled with a if (debug_mode)
+ test.
+ Usage: test_name -d
+ */
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "d:");
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 'd': /* debug mode */
+ debug_mode = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ /* main test */
+ if (debug_mode) {
+ printf("Enter number of iterations: \n");
+ scanf("%d", &_iterations);
+ printf("Enter number of clients : \n");
+ scanf("%d", &_clients);
+ printf("Enter size of client data : \n");
+ scanf("%d", &_client_data);
+ printf("Enter size of server data : \n");
+ scanf("%d", &_server_data);
+ }
+ else
+ {
+ _iterations = 7;
+ _clients = 7;
+ _client_data = 100;
+ _server_data = 100;
+ }
+
+ if (debug_mode) {
+ printf("\n\n%d iterations with %d client threads.\n",
+ _iterations, _clients);
+ printf("Sending %d bytes of client data and %d bytes of server data\n",
+ _client_data, _server_data);
+ }
+ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
+ PR_STDIO_INIT();
+
+ PR_SetThreadRecycleMode(64);
+
+ ServerStateCVLock = PR_NewLock();
+ ServerStateCV = PR_NewCondVar(ServerStateCVLock);
+
+
+ Measure(do_workKK, "server loop kernel/kernel");
+
+ PR_Cleanup();
+
+ if(failed_already) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+
+}
diff --git a/nsprpub/pr/tests/servr_ku.c b/nsprpub/pr/tests/servr_ku.c
new file mode 100644
index 0000000000..d0c446f52f
--- /dev/null
+++ b/nsprpub/pr/tests/servr_ku.c
@@ -0,0 +1,639 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/***********************************************************************
+**
+** This server simulates a server running in loopback mode.
+**
+** The idea is that a single server is created. The server initially creates
+** a number of worker threads. Then, with the server running, a number of
+** clients are created which start requesting service from the server.
+**
+**
+** Modification History:
+** 19-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
+** The debug mode will print all of the printfs associated with this test.
+** The regress mode will be the default mode. Since the regress tool limits
+** the output to a one line status:PASS or FAIL,all of the printf statements
+** have been handled with an if (debug_mode) statement.
+** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to
+** recognize the return code from tha main program.
+***********************************************************************/
+
+/***********************************************************************
+** Includes
+***********************************************************************/
+/* Used to get the command line option */
+#include "plgetopt.h"
+
+#include "nspr.h"
+#include "pprthred.h"
+
+#include <string.h>
+
+#define PORT 15004
+#define THREAD_STACKSIZE 0
+
+static int _iterations = 1000;
+static int _clients = 1;
+static int _client_data = 250;
+static int _server_data = (8*1024);
+
+static PRThreadScope ServerScope, ClientScope;
+
+#define SERVER "Server"
+#define MAIN "Main"
+
+#define SERVER_STATE_STARTUP 0
+#define SERVER_STATE_READY 1
+#define SERVER_STATE_DYING 2
+#define SERVER_STATE_DEAD 4
+int ServerState;
+PRLock *ServerStateCVLock;
+PRCondVar *ServerStateCV;
+
+#ifdef DEBUGPRINTS
+#define DPRINTF printf
+#else
+#define DPRINTF
+#endif
+
+PRIntn failed_already=0;
+PRIntn debug_mode;
+
+static void do_work(void);
+
+/* --- Server state functions --------------------------------------------- */
+void
+SetServerState(char *waiter, PRInt32 state)
+{
+ PR_Lock(ServerStateCVLock);
+ ServerState = state;
+ PR_NotifyCondVar(ServerStateCV);
+
+ if (debug_mode) {
+ DPRINTF("\t%s changed state to %d\n", waiter, state);
+ }
+
+ PR_Unlock(ServerStateCVLock);
+}
+
+int
+WaitServerState(char *waiter, PRInt32 state)
+{
+ PRInt32 rv;
+
+ PR_Lock(ServerStateCVLock);
+
+ if (debug_mode) {
+ DPRINTF("\t%s waiting for state %d\n", waiter, state);
+ }
+
+ while(!(ServerState & state)) {
+ PR_WaitCondVar(ServerStateCV, PR_INTERVAL_NO_TIMEOUT);
+ }
+ rv = ServerState;
+
+ if (debug_mode) DPRINTF("\t%s resuming from wait for state %d; state now %d\n",
+ waiter, state, ServerState);
+ PR_Unlock(ServerStateCVLock);
+
+ return rv;
+}
+
+/* --- Server Functions ------------------------------------------- */
+
+PRLock *workerThreadsLock;
+PRInt32 workerThreads;
+PRInt32 workerThreadsBusy;
+
+void
+WorkerThreadFunc(void *_listenSock)
+{
+ PRFileDesc *listenSock = (PRFileDesc *)_listenSock;
+ PRInt32 bytesRead;
+ PRInt32 bytesWritten;
+ char *dataBuf;
+ char *sendBuf;
+
+ if (debug_mode) DPRINTF("\tServer buffer is %d bytes; %d data, %d netaddrs\n",
+ _client_data+(2*sizeof(PRNetAddr))+32, _client_data, (2*sizeof(PRNetAddr))+32);
+ dataBuf = (char *)PR_MALLOC(_client_data + 2*sizeof(PRNetAddr) + 32);
+ if (!dataBuf)
+ if (debug_mode) {
+ printf("\tServer could not malloc space!?\n");
+ }
+ sendBuf = (char *)PR_MALLOC(_server_data *sizeof(char));
+ if (!sendBuf)
+ if (debug_mode) {
+ printf("\tServer could not malloc space!?\n");
+ }
+
+ if (debug_mode) {
+ DPRINTF("\tServer worker thread running\n");
+ }
+
+ while(1) {
+ PRInt32 bytesToRead = _client_data;
+ PRInt32 bytesToWrite = _server_data;
+ PRFileDesc *newSock;
+ PRNetAddr *rAddr;
+ PRInt32 loops = 0;
+
+ loops++;
+
+ if (debug_mode) {
+ DPRINTF("\tServer thread going into accept\n");
+ }
+
+ bytesRead = PR_AcceptRead(listenSock,
+ &newSock,
+ &rAddr,
+ dataBuf,
+ bytesToRead,
+ PR_INTERVAL_NO_TIMEOUT);
+
+ if (bytesRead < 0) {
+ if (debug_mode) {
+ printf("\tServer error in accept (%d)\n", bytesRead);
+ }
+ continue;
+ }
+
+ if (debug_mode) {
+ DPRINTF("\tServer accepted connection (%d bytes)\n", bytesRead);
+ }
+
+ PR_AtomicIncrement(&workerThreadsBusy);
+ if (workerThreadsBusy == workerThreads) {
+ PR_Lock(workerThreadsLock);
+ if (workerThreadsBusy == workerThreads) {
+ PRThread *WorkerThread;
+
+ WorkerThread = PR_CreateThread(
+ PR_SYSTEM_THREAD,
+ WorkerThreadFunc,
+ listenSock,
+ PR_PRIORITY_NORMAL,
+ ServerScope,
+ PR_UNJOINABLE_THREAD,
+ THREAD_STACKSIZE);
+
+ if (!WorkerThread) {
+ if (debug_mode) {
+ printf("Error creating client thread %d\n", workerThreads);
+ }
+ } else {
+ PR_AtomicIncrement(&workerThreads);
+ if (debug_mode) {
+ DPRINTF("\tServer creates worker (%d)\n", workerThreads);
+ }
+ }
+ }
+ PR_Unlock(workerThreadsLock);
+ }
+
+ bytesToRead -= bytesRead;
+ while (bytesToRead) {
+ bytesRead = PR_Recv(newSock,
+ dataBuf,
+ bytesToRead,
+ 0,
+ PR_INTERVAL_NO_TIMEOUT);
+ if (bytesRead < 0) {
+ if (debug_mode) {
+ printf("\tServer error receiving data (%d)\n", bytesRead);
+ }
+ continue;
+ }
+ if (debug_mode) {
+ DPRINTF("\tServer received %d bytes\n", bytesRead);
+ }
+ }
+
+ bytesWritten = PR_Send(newSock,
+ sendBuf,
+ bytesToWrite,
+ 0,
+ PR_INTERVAL_NO_TIMEOUT);
+ if (bytesWritten != _server_data) {
+ if (debug_mode) printf("\tError sending data to client (%d, %d)\n",
+ bytesWritten, PR_GetOSError());
+ } else {
+ if (debug_mode) {
+ DPRINTF("\tServer sent %d bytes\n", bytesWritten);
+ }
+ }
+
+ PR_Close(newSock);
+ PR_AtomicDecrement(&workerThreadsBusy);
+ }
+}
+
+PRFileDesc *
+ServerSetup(void)
+{
+ PRFileDesc *listenSocket;
+ PRSocketOptionData sockOpt;
+ PRNetAddr serverAddr;
+ PRThread *WorkerThread;
+
+ if ( (listenSocket = PR_NewTCPSocket()) == NULL) {
+ if (debug_mode) {
+ printf("\tServer error creating listen socket\n");
+ }
+ else {
+ failed_already=1;
+ }
+ return NULL;
+ }
+
+ sockOpt.option = PR_SockOpt_Reuseaddr;
+ sockOpt.value.reuse_addr = PR_TRUE;
+ if ( PR_SetSocketOption(listenSocket, &sockOpt) == PR_FAILURE) {
+ if (debug_mode) printf("\tServer error setting socket option: OS error %d\n",
+ PR_GetOSError());
+ else {
+ failed_already=1;
+ }
+ PR_Close(listenSocket);
+ return NULL;
+ }
+
+ memset(&serverAddr, 0, sizeof(PRNetAddr));
+ serverAddr.inet.family = PR_AF_INET;
+ serverAddr.inet.port = PR_htons(PORT);
+ serverAddr.inet.ip = PR_htonl(PR_INADDR_ANY);
+
+ if ( PR_Bind(listenSocket, &serverAddr) == PR_FAILURE) {
+ if (debug_mode) printf("\tServer error binding to server address: OS error %d\n",
+ PR_GetOSError());
+ else {
+ failed_already=1;
+ }
+ PR_Close(listenSocket);
+ return NULL;
+ }
+
+ if ( PR_Listen(listenSocket, 128) == PR_FAILURE) {
+ if (debug_mode) {
+ printf("\tServer error listening to server socket\n");
+ }
+ else {
+ failed_already=1;
+ }
+ PR_Close(listenSocket);
+
+ return NULL;
+ }
+
+ /* Create Clients */
+ workerThreads = 0;
+ workerThreadsBusy = 0;
+
+ workerThreadsLock = PR_NewLock();
+
+ WorkerThread = PR_CreateThread(
+ PR_SYSTEM_THREAD,
+ WorkerThreadFunc,
+ listenSocket,
+ PR_PRIORITY_NORMAL,
+ ServerScope,
+ PR_UNJOINABLE_THREAD,
+ THREAD_STACKSIZE);
+
+ if (!WorkerThread) {
+ if (debug_mode) {
+ printf("error creating working thread\n");
+ }
+ PR_Close(listenSocket);
+ return NULL;
+ }
+ PR_AtomicIncrement(&workerThreads);
+ if (debug_mode) {
+ DPRINTF("\tServer created primordial worker thread\n");
+ }
+
+ return listenSocket;
+}
+
+/* The main server loop */
+void
+ServerThreadFunc(void *unused)
+{
+ PRFileDesc *listenSocket;
+
+ /* Do setup */
+ listenSocket = ServerSetup();
+
+ if (!listenSocket) {
+ SetServerState(SERVER, SERVER_STATE_DEAD);
+ } else {
+
+ if (debug_mode) {
+ DPRINTF("\tServer up\n");
+ }
+
+ /* Tell clients they can start now. */
+ SetServerState(SERVER, SERVER_STATE_READY);
+
+ /* Now wait for server death signal */
+ WaitServerState(SERVER, SERVER_STATE_DYING);
+
+ /* Cleanup */
+ SetServerState(SERVER, SERVER_STATE_DEAD);
+ }
+}
+
+/* --- Client Functions ------------------------------------------- */
+
+PRInt32 numRequests;
+PRInt32 numClients;
+PRMonitor *clientMonitor;
+
+void
+ClientThreadFunc(void *unused)
+{
+ PRNetAddr serverAddr;
+ PRFileDesc *clientSocket;
+ char *sendBuf;
+ char *recvBuf;
+ PRInt32 rv;
+ PRInt32 bytesNeeded;
+
+ sendBuf = (char *)PR_MALLOC(_client_data * sizeof(char));
+ if (!sendBuf)
+ if (debug_mode) {
+ printf("\tClient could not malloc space!?\n");
+ }
+ recvBuf = (char *)PR_MALLOC(_server_data * sizeof(char));
+ if (!recvBuf)
+ if (debug_mode) {
+ printf("\tClient could not malloc space!?\n");
+ }
+
+ memset(&serverAddr, 0, sizeof(PRNetAddr));
+ serverAddr.inet.family = PR_AF_INET;
+ serverAddr.inet.port = PR_htons(PORT);
+ serverAddr.inet.ip = PR_htonl(PR_INADDR_LOOPBACK);
+
+ while(numRequests > 0) {
+
+ if ( (numRequests % 10) == 0 )
+ if (debug_mode) {
+ printf(".");
+ }
+ if (debug_mode) {
+ DPRINTF("\tClient starting request %d\n", numRequests);
+ }
+
+ clientSocket = PR_NewTCPSocket();
+ if (!clientSocket) {
+ if (debug_mode) printf("Client error creating socket: OS error %d\n",
+ PR_GetOSError());
+ continue;
+ }
+
+ if (debug_mode) {
+ DPRINTF("\tClient connecting\n");
+ }
+
+ rv = PR_Connect(clientSocket,
+ &serverAddr,
+ PR_INTERVAL_NO_TIMEOUT);
+ if (!clientSocket) {
+ if (debug_mode) {
+ printf("\tClient error connecting\n");
+ }
+ continue;
+ }
+
+ if (debug_mode) {
+ DPRINTF("\tClient connected\n");
+ }
+
+ rv = PR_Send(clientSocket,
+ sendBuf,
+ _client_data,
+ 0,
+ PR_INTERVAL_NO_TIMEOUT);
+ if (rv != _client_data) {
+ if (debug_mode) {
+ printf("Client error sending data (%d)\n", rv);
+ }
+ PR_Close(clientSocket);
+ continue;
+ }
+
+ if (debug_mode) {
+ DPRINTF("\tClient sent %d bytes\n", rv);
+ }
+
+ bytesNeeded = _server_data;
+ while(bytesNeeded) {
+ rv = PR_Recv(clientSocket,
+ recvBuf,
+ bytesNeeded,
+ 0,
+ PR_INTERVAL_NO_TIMEOUT);
+ if (rv <= 0) {
+ if (debug_mode) printf("Client error receiving data (%d) (%d/%d)\n",
+ rv, (_server_data - bytesNeeded), _server_data);
+ break;
+ }
+ if (debug_mode) {
+ DPRINTF("\tClient received %d bytes; need %d more\n", rv, bytesNeeded - rv);
+ }
+ bytesNeeded -= rv;
+ }
+
+ PR_Close(clientSocket);
+
+ PR_AtomicDecrement(&numRequests);
+ }
+
+ PR_EnterMonitor(clientMonitor);
+ --numClients;
+ PR_Notify(clientMonitor);
+ PR_ExitMonitor(clientMonitor);
+
+ PR_DELETE(sendBuf);
+ PR_DELETE(recvBuf);
+}
+
+void
+RunClients(void)
+{
+ PRInt32 index;
+
+ numRequests = _iterations;
+ numClients = _clients;
+ clientMonitor = PR_NewMonitor();
+
+ for (index=0; index<_clients; index++) {
+ PRThread *clientThread;
+
+
+ clientThread = PR_CreateThread(
+ PR_USER_THREAD,
+ ClientThreadFunc,
+ NULL,
+ PR_PRIORITY_NORMAL,
+ ClientScope,
+ PR_UNJOINABLE_THREAD,
+ THREAD_STACKSIZE);
+
+ if (!clientThread) {
+ if (debug_mode) {
+ printf("\terror creating client thread %d\n", index);
+ }
+ } else if (debug_mode) {
+ DPRINTF("\tMain created client %d/%d\n", index+1, _clients);
+ }
+
+ }
+
+ PR_EnterMonitor(clientMonitor);
+ while(numClients) {
+ PR_Wait(clientMonitor, PR_INTERVAL_NO_TIMEOUT);
+ }
+ PR_ExitMonitor(clientMonitor);
+}
+
+/* --- Main Function ---------------------------------------------- */
+
+static
+void do_work()
+{
+ PRThread *ServerThread;
+ PRInt32 state;
+
+ SetServerState(MAIN, SERVER_STATE_STARTUP);
+ ServerThread = PR_CreateThread(
+ PR_USER_THREAD,
+ ServerThreadFunc,
+ NULL,
+ PR_PRIORITY_NORMAL,
+ ServerScope,
+ PR_JOINABLE_THREAD,
+ THREAD_STACKSIZE);
+ if (!ServerThread) {
+ if (debug_mode) {
+ printf("error creating main server thread\n");
+ }
+ return;
+ }
+
+ /* Wait for server to be ready */
+ state = WaitServerState(MAIN, SERVER_STATE_READY|SERVER_STATE_DEAD);
+
+ if (!(state & SERVER_STATE_DEAD)) {
+ /* Run Test Clients */
+ RunClients();
+
+ /* Send death signal to server */
+ SetServerState(MAIN, SERVER_STATE_DYING);
+ }
+
+ PR_JoinThread(ServerThread);
+}
+
+
+static void do_workKU(void)
+{
+ ServerScope = PR_GLOBAL_THREAD;
+ ClientScope = PR_LOCAL_THREAD;
+ do_work();
+}
+
+
+
+static void Measure(void (*func)(void), const char *msg)
+{
+ PRIntervalTime start, stop;
+ double d;
+
+ start = PR_IntervalNow();
+ (*func)();
+ stop = PR_IntervalNow();
+
+ d = (double)PR_IntervalToMicroseconds(stop - start);
+
+ if (debug_mode) {
+ printf("\n%40s: %6.2f usec\n", msg, d / _iterations);
+ }
+}
+
+
+int main(int argc, char **argv)
+{
+ /* The command line argument: -d is used to determine if the test is being run
+ in debug mode. The regress tool requires only one line output:PASS or FAIL.
+ All of the printfs associated with this test has been handled with a if (debug_mode)
+ test.
+ Usage: test_name -d
+ */
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "d:");
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 'd': /* debug mode */
+ debug_mode = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ /* main test */
+ if (debug_mode) {
+ printf("Enter number of iterations: \n");
+ scanf("%d", &_iterations);
+ printf("Enter number of clients : \n");
+ scanf("%d", &_clients);
+ printf("Enter size of client data : \n");
+ scanf("%d", &_client_data);
+ printf("Enter size of server data : \n");
+ scanf("%d", &_server_data);
+ }
+ else
+ {
+ _iterations = 7;
+ _clients = 7;
+ _client_data = 100;
+ _server_data = 100;
+ }
+
+ if (debug_mode) {
+ printf("\n\n%d iterations with %d client threads.\n",
+ _iterations, _clients);
+ printf("Sending %d bytes of client data and %d bytes of server data\n",
+ _client_data, _server_data);
+ }
+ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
+ PR_STDIO_INIT();
+
+ PR_SetThreadRecycleMode(64);
+
+ ServerStateCVLock = PR_NewLock();
+ ServerStateCV = PR_NewCondVar(ServerStateCVLock);
+
+ Measure(do_workKU, "server loop kernel/user");
+
+ PR_Cleanup();
+ if(failed_already) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+
+}
diff --git a/nsprpub/pr/tests/servr_uk.c b/nsprpub/pr/tests/servr_uk.c
new file mode 100644
index 0000000000..bd97c8f35a
--- /dev/null
+++ b/nsprpub/pr/tests/servr_uk.c
@@ -0,0 +1,640 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/***********************************************************************
+**
+** This server simulates a server running in loopback mode.
+**
+** The idea is that a single server is created. The server initially creates
+** a number of worker threads. Then, with the server running, a number of
+** clients are created which start requesting service from the server.
+**
+**
+** Modification History:
+** 19-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
+** The debug mode will print all of the printfs associated with this test.
+** The regress mode will be the default mode. Since the regress tool limits
+** the output to a one line status:PASS or FAIL,all of the printf statements
+** have been handled with an if (debug_mode) statement.
+** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to
+** recognize the return code from tha main program.
+***********************************************************************/
+
+/***********************************************************************
+** Includes
+***********************************************************************/
+/* Used to get the command line option */
+#include "plgetopt.h"
+
+#include "nspr.h"
+#include "pprthred.h"
+
+#include <string.h>
+
+#define PORT 15004
+#define THREAD_STACKSIZE 0
+
+static int _iterations = 1000;
+static int _clients = 1;
+static int _client_data = 250;
+static int _server_data = (8*1024);
+
+static PRThreadScope ServerScope, ClientScope;
+
+#define SERVER "Server"
+#define MAIN "Main"
+
+#define SERVER_STATE_STARTUP 0
+#define SERVER_STATE_READY 1
+#define SERVER_STATE_DYING 2
+#define SERVER_STATE_DEAD 4
+int ServerState;
+PRLock *ServerStateCVLock;
+PRCondVar *ServerStateCV;
+
+#ifdef DEBUGPRINTS
+#define DPRINTF printf
+#else
+#define DPRINTF
+#endif
+
+PRIntn failed_already=0;
+PRIntn debug_mode;
+
+
+
+static void do_work(void);
+
+/* --- Server state functions --------------------------------------------- */
+void
+SetServerState(char *waiter, PRInt32 state)
+{
+ PR_Lock(ServerStateCVLock);
+ ServerState = state;
+ PR_NotifyCondVar(ServerStateCV);
+
+ if (debug_mode) {
+ DPRINTF("\t%s changed state to %d\n", waiter, state);
+ }
+
+ PR_Unlock(ServerStateCVLock);
+}
+
+int
+WaitServerState(char *waiter, PRInt32 state)
+{
+ PRInt32 rv;
+
+ PR_Lock(ServerStateCVLock);
+
+ if (debug_mode) {
+ DPRINTF("\t%s waiting for state %d\n", waiter, state);
+ }
+
+ while(!(ServerState & state)) {
+ PR_WaitCondVar(ServerStateCV, PR_INTERVAL_NO_TIMEOUT);
+ }
+ rv = ServerState;
+
+ if (debug_mode) DPRINTF("\t%s resuming from wait for state %d; state now %d\n",
+ waiter, state, ServerState);
+ PR_Unlock(ServerStateCVLock);
+
+ return rv;
+}
+
+/* --- Server Functions ------------------------------------------- */
+
+PRLock *workerThreadsLock;
+PRInt32 workerThreads;
+PRInt32 workerThreadsBusy;
+
+void
+WorkerThreadFunc(void *_listenSock)
+{
+ PRFileDesc *listenSock = (PRFileDesc *)_listenSock;
+ PRInt32 bytesRead;
+ PRInt32 bytesWritten;
+ char *dataBuf;
+ char *sendBuf;
+
+ if (debug_mode) DPRINTF("\tServer buffer is %d bytes; %d data, %d netaddrs\n",
+ _client_data+(2*sizeof(PRNetAddr))+32, _client_data, (2*sizeof(PRNetAddr))+32);
+ dataBuf = (char *)PR_MALLOC(_client_data + 2*sizeof(PRNetAddr) + 32);
+ if (!dataBuf)
+ if (debug_mode) {
+ printf("\tServer could not malloc space!?\n");
+ }
+ sendBuf = (char *)PR_MALLOC(_server_data *sizeof(char));
+ if (!sendBuf)
+ if (debug_mode) {
+ printf("\tServer could not malloc space!?\n");
+ }
+
+ if (debug_mode) {
+ DPRINTF("\tServer worker thread running\n");
+ }
+
+ while(1) {
+ PRInt32 bytesToRead = _client_data;
+ PRInt32 bytesToWrite = _server_data;
+ PRFileDesc *newSock;
+ PRNetAddr *rAddr;
+ PRInt32 loops = 0;
+
+ loops++;
+
+ if (debug_mode) {
+ DPRINTF("\tServer thread going into accept\n");
+ }
+
+ bytesRead = PR_AcceptRead(listenSock,
+ &newSock,
+ &rAddr,
+ dataBuf,
+ bytesToRead,
+ PR_INTERVAL_NO_TIMEOUT);
+
+ if (bytesRead < 0) {
+ if (debug_mode) {
+ printf("\tServer error in accept (%d)\n", bytesRead);
+ }
+ continue;
+ }
+
+ if (debug_mode) {
+ DPRINTF("\tServer accepted connection (%d bytes)\n", bytesRead);
+ }
+
+ PR_AtomicIncrement(&workerThreadsBusy);
+ if (workerThreadsBusy == workerThreads) {
+ PR_Lock(workerThreadsLock);
+ if (workerThreadsBusy == workerThreads) {
+ PRThread *WorkerThread;
+
+ WorkerThread = PR_CreateThread(
+ PR_SYSTEM_THREAD,
+ WorkerThreadFunc,
+ listenSock,
+ PR_PRIORITY_NORMAL,
+ ServerScope,
+ PR_UNJOINABLE_THREAD,
+ THREAD_STACKSIZE);
+
+ if (!WorkerThread) {
+ if (debug_mode) {
+ printf("Error creating client thread %d\n", workerThreads);
+ }
+ } else {
+ PR_AtomicIncrement(&workerThreads);
+ if (debug_mode) {
+ DPRINTF("\tServer creates worker (%d)\n", workerThreads);
+ }
+ }
+ }
+ PR_Unlock(workerThreadsLock);
+ }
+
+ bytesToRead -= bytesRead;
+ while (bytesToRead) {
+ bytesRead = PR_Recv(newSock,
+ dataBuf,
+ bytesToRead,
+ 0,
+ PR_INTERVAL_NO_TIMEOUT);
+ if (bytesRead < 0) {
+ if (debug_mode) {
+ printf("\tServer error receiving data (%d)\n", bytesRead);
+ }
+ continue;
+ }
+ if (debug_mode) {
+ DPRINTF("\tServer received %d bytes\n", bytesRead);
+ }
+ }
+
+ bytesWritten = PR_Send(newSock,
+ sendBuf,
+ bytesToWrite,
+ 0,
+ PR_INTERVAL_NO_TIMEOUT);
+ if (bytesWritten != _server_data) {
+ if (debug_mode) printf("\tError sending data to client (%d, %d)\n",
+ bytesWritten, PR_GetOSError());
+ } else {
+ if (debug_mode) {
+ DPRINTF("\tServer sent %d bytes\n", bytesWritten);
+ }
+ }
+
+ PR_Close(newSock);
+ PR_AtomicDecrement(&workerThreadsBusy);
+ }
+}
+
+PRFileDesc *
+ServerSetup(void)
+{
+ PRFileDesc *listenSocket;
+ PRSocketOptionData sockOpt;
+ PRNetAddr serverAddr;
+ PRThread *WorkerThread;
+
+ if ( (listenSocket = PR_NewTCPSocket()) == NULL) {
+ if (debug_mode) {
+ printf("\tServer error creating listen socket\n");
+ }
+ else {
+ return NULL;
+ }
+ }
+
+ sockOpt.option = PR_SockOpt_Reuseaddr;
+ sockOpt.value.reuse_addr = PR_TRUE;
+ if ( PR_SetSocketOption(listenSocket, &sockOpt) == PR_FAILURE) {
+ if (debug_mode) printf("\tServer error setting socket option: OS error %d\n",
+ PR_GetOSError());
+ else {
+ failed_already=1;
+ }
+ PR_Close(listenSocket);
+ return NULL;
+ }
+
+ memset(&serverAddr, 0, sizeof(PRNetAddr));
+ serverAddr.inet.family = PR_AF_INET;
+ serverAddr.inet.port = PR_htons(PORT);
+ serverAddr.inet.ip = PR_htonl(PR_INADDR_ANY);
+
+ if ( PR_Bind(listenSocket, &serverAddr) == PR_FAILURE) {
+ if (debug_mode) printf("\tServer error binding to server address: OS error %d\n",
+ PR_GetOSError());
+ else {
+ failed_already=1;
+ }
+ PR_Close(listenSocket);
+ return NULL;
+ }
+
+ if ( PR_Listen(listenSocket, 128) == PR_FAILURE) {
+ if (debug_mode) {
+ printf("\tServer error listening to server socket\n");
+ }
+ else {
+ failed_already=1;
+ }
+ PR_Close(listenSocket);
+
+ return NULL;
+ }
+
+ /* Create Clients */
+ workerThreads = 0;
+ workerThreadsBusy = 0;
+
+ workerThreadsLock = PR_NewLock();
+
+ WorkerThread = PR_CreateThread(
+ PR_SYSTEM_THREAD,
+ WorkerThreadFunc,
+ listenSocket,
+ PR_PRIORITY_NORMAL,
+ ServerScope,
+ PR_UNJOINABLE_THREAD,
+ THREAD_STACKSIZE);
+
+ if (!WorkerThread) {
+ if (debug_mode) {
+ printf("error creating working thread\n");
+ }
+ PR_Close(listenSocket);
+ return NULL;
+ }
+ PR_AtomicIncrement(&workerThreads);
+ if (debug_mode) {
+ DPRINTF("\tServer created primordial worker thread\n");
+ }
+
+ return listenSocket;
+}
+
+/* The main server loop */
+void
+ServerThreadFunc(void *unused)
+{
+ PRFileDesc *listenSocket;
+
+ /* Do setup */
+ listenSocket = ServerSetup();
+
+ if (!listenSocket) {
+ SetServerState(SERVER, SERVER_STATE_DEAD);
+ } else {
+
+ if (debug_mode) {
+ DPRINTF("\tServer up\n");
+ }
+
+ /* Tell clients they can start now. */
+ SetServerState(SERVER, SERVER_STATE_READY);
+
+ /* Now wait for server death signal */
+ WaitServerState(SERVER, SERVER_STATE_DYING);
+
+ /* Cleanup */
+ SetServerState(SERVER, SERVER_STATE_DEAD);
+ }
+}
+
+/* --- Client Functions ------------------------------------------- */
+
+PRInt32 numRequests;
+PRInt32 numClients;
+PRMonitor *clientMonitor;
+
+void
+ClientThreadFunc(void *unused)
+{
+ PRNetAddr serverAddr;
+ PRFileDesc *clientSocket;
+ char *sendBuf;
+ char *recvBuf;
+ PRInt32 rv;
+ PRInt32 bytesNeeded;
+
+ sendBuf = (char *)PR_MALLOC(_client_data * sizeof(char));
+ if (!sendBuf)
+ if (debug_mode) {
+ printf("\tClient could not malloc space!?\n");
+ }
+ recvBuf = (char *)PR_MALLOC(_server_data * sizeof(char));
+ if (!recvBuf)
+ if (debug_mode) {
+ printf("\tClient could not malloc space!?\n");
+ }
+
+ memset(&serverAddr, 0, sizeof(PRNetAddr));
+ serverAddr.inet.family = PR_AF_INET;
+ serverAddr.inet.port = PR_htons(PORT);
+ serverAddr.inet.ip = PR_htonl(PR_INADDR_LOOPBACK);
+
+ while(numRequests > 0) {
+
+ if ( (numRequests % 10) == 0 )
+ if (debug_mode) {
+ printf(".");
+ }
+ if (debug_mode) {
+ DPRINTF("\tClient starting request %d\n", numRequests);
+ }
+
+ clientSocket = PR_NewTCPSocket();
+ if (!clientSocket) {
+ if (debug_mode) printf("Client error creating socket: OS error %d\n",
+ PR_GetOSError());
+ continue;
+ }
+
+ if (debug_mode) {
+ DPRINTF("\tClient connecting\n");
+ }
+
+ rv = PR_Connect(clientSocket,
+ &serverAddr,
+ PR_INTERVAL_NO_TIMEOUT);
+ if (!clientSocket) {
+ if (debug_mode) {
+ printf("\tClient error connecting\n");
+ }
+ continue;
+ }
+
+ if (debug_mode) {
+ DPRINTF("\tClient connected\n");
+ }
+
+ rv = PR_Send(clientSocket,
+ sendBuf,
+ _client_data,
+ 0,
+ PR_INTERVAL_NO_TIMEOUT);
+ if (rv != _client_data) {
+ if (debug_mode) {
+ printf("Client error sending data (%d)\n", rv);
+ }
+ PR_Close(clientSocket);
+ continue;
+ }
+
+ if (debug_mode) {
+ DPRINTF("\tClient sent %d bytes\n", rv);
+ }
+
+ bytesNeeded = _server_data;
+ while(bytesNeeded) {
+ rv = PR_Recv(clientSocket,
+ recvBuf,
+ bytesNeeded,
+ 0,
+ PR_INTERVAL_NO_TIMEOUT);
+ if (rv <= 0) {
+ if (debug_mode) printf("Client error receiving data (%d) (%d/%d)\n",
+ rv, (_server_data - bytesNeeded), _server_data);
+ break;
+ }
+ if (debug_mode) {
+ DPRINTF("\tClient received %d bytes; need %d more\n", rv, bytesNeeded - rv);
+ }
+ bytesNeeded -= rv;
+ }
+
+ PR_Close(clientSocket);
+
+ PR_AtomicDecrement(&numRequests);
+ }
+
+ PR_EnterMonitor(clientMonitor);
+ --numClients;
+ PR_Notify(clientMonitor);
+ PR_ExitMonitor(clientMonitor);
+
+ PR_DELETE(sendBuf);
+ PR_DELETE(recvBuf);
+}
+
+void
+RunClients(void)
+{
+ PRInt32 index;
+
+ numRequests = _iterations;
+ numClients = _clients;
+ clientMonitor = PR_NewMonitor();
+
+ for (index=0; index<_clients; index++) {
+ PRThread *clientThread;
+
+
+ clientThread = PR_CreateThread(
+ PR_USER_THREAD,
+ ClientThreadFunc,
+ NULL,
+ PR_PRIORITY_NORMAL,
+ ClientScope,
+ PR_UNJOINABLE_THREAD,
+ THREAD_STACKSIZE);
+
+ if (!clientThread) {
+ if (debug_mode) {
+ printf("\terror creating client thread %d\n", index);
+ }
+ } else if (debug_mode) {
+ DPRINTF("\tMain created client %d/%d\n", index+1, _clients);
+ }
+
+ }
+
+ PR_EnterMonitor(clientMonitor);
+ while(numClients) {
+ PR_Wait(clientMonitor, PR_INTERVAL_NO_TIMEOUT);
+ }
+ PR_ExitMonitor(clientMonitor);
+}
+
+/* --- Main Function ---------------------------------------------- */
+
+static
+void do_work()
+{
+ PRThread *ServerThread;
+ PRInt32 state;
+
+ SetServerState(MAIN, SERVER_STATE_STARTUP);
+ ServerThread = PR_CreateThread(
+ PR_USER_THREAD,
+ ServerThreadFunc,
+ NULL,
+ PR_PRIORITY_NORMAL,
+ ServerScope,
+ PR_JOINABLE_THREAD,
+ THREAD_STACKSIZE);
+ if (!ServerThread) {
+ if (debug_mode) {
+ printf("error creating main server thread\n");
+ }
+ return;
+ }
+
+ /* Wait for server to be ready */
+ state = WaitServerState(MAIN, SERVER_STATE_READY|SERVER_STATE_DEAD);
+
+ if (!(state & SERVER_STATE_DEAD)) {
+ /* Run Test Clients */
+ RunClients();
+
+ /* Send death signal to server */
+ SetServerState(MAIN, SERVER_STATE_DYING);
+ }
+
+ PR_JoinThread(ServerThread);
+}
+
+
+static void do_workUK(void)
+{
+ ServerScope = PR_LOCAL_THREAD;
+ ClientScope = PR_GLOBAL_THREAD;
+ do_work();
+}
+
+
+
+static void Measure(void (*func)(void), const char *msg)
+{
+ PRIntervalTime start, stop;
+ double d;
+
+ start = PR_IntervalNow();
+ (*func)();
+ stop = PR_IntervalNow();
+
+ d = (double)PR_IntervalToMicroseconds(stop - start);
+
+ if (debug_mode) {
+ printf("\n%40s: %6.2f usec\n", msg, d / _iterations);
+ }
+}
+
+
+int main(int argc, char **argv)
+{
+ /* The command line argument: -d is used to determine if the test is being run
+ in debug mode. The regress tool requires only one line output:PASS or FAIL.
+ All of the printfs associated with this test has been handled with a if (debug_mode)
+ test.
+ Usage: test_name -d
+ */
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "d:");
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 'd': /* debug mode */
+ debug_mode = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ /* main test */
+ if (debug_mode) {
+ printf("Enter number of iterations: \n");
+ scanf("%d", &_iterations);
+ printf("Enter number of clients : \n");
+ scanf("%d", &_clients);
+ printf("Enter size of client data : \n");
+ scanf("%d", &_client_data);
+ printf("Enter size of server data : \n");
+ scanf("%d", &_server_data);
+ }
+ else
+ {
+ _iterations = 7;
+ _clients = 7;
+ _client_data = 100;
+ _server_data = 100;
+ }
+
+ if (debug_mode) {
+ printf("\n\n%d iterations with %d client threads.\n",
+ _iterations, _clients);
+ printf("Sending %d bytes of client data and %d bytes of server data\n",
+ _client_data, _server_data);
+ }
+ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
+ PR_STDIO_INIT();
+
+ PR_SetThreadRecycleMode(64);
+
+ ServerStateCVLock = PR_NewLock();
+ ServerStateCV = PR_NewCondVar(ServerStateCVLock);
+
+ Measure(do_workUK, "server loop user/kernel");
+
+ PR_Cleanup();
+
+ if(failed_already) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+}
diff --git a/nsprpub/pr/tests/servr_uu.c b/nsprpub/pr/tests/servr_uu.c
new file mode 100644
index 0000000000..8e77d8fa82
--- /dev/null
+++ b/nsprpub/pr/tests/servr_uu.c
@@ -0,0 +1,640 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/***********************************************************************
+**
+** This server simulates a server running in loopback mode.
+**
+** The idea is that a single server is created. The server initially creates
+** a number of worker threads. Then, with the server running, a number of
+** clients are created which start requesting service from the server.
+**
+**
+** Modification History:
+** 19-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
+** The debug mode will print all of the printfs associated with this test.
+** The regress mode will be the default mode. Since the regress tool limits
+** the output to a one line status:PASS or FAIL,all of the printf statements
+** have been handled with an if (debug_mode) statement.
+** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to
+** recognize the return code from tha main program.
+***********************************************************************/
+
+/***********************************************************************
+** Includes
+***********************************************************************/
+/* Used to get the command line option */
+#include "plgetopt.h"
+
+#include "nspr.h"
+#include "pprthred.h"
+
+#include <string.h>
+
+#define PORT 15004
+#define THREAD_STACKSIZE 0
+
+static int _iterations = 1000;
+static int _clients = 1;
+static int _client_data = 250;
+static int _server_data = (8*1024);
+
+static PRThreadScope ServerScope, ClientScope;
+
+#define SERVER "Server"
+#define MAIN "Main"
+
+#define SERVER_STATE_STARTUP 0
+#define SERVER_STATE_READY 1
+#define SERVER_STATE_DYING 2
+#define SERVER_STATE_DEAD 4
+int ServerState;
+PRLock *ServerStateCVLock;
+PRCondVar *ServerStateCV;
+
+#ifdef DEBUGPRINTS
+#define DPRINTF printf
+#else
+#define DPRINTF
+#endif
+
+PRIntn failed_already=0;
+PRIntn debug_mode;
+
+static void do_work(void);
+
+/* --- Server state functions --------------------------------------------- */
+void
+SetServerState(char *waiter, PRInt32 state)
+{
+ PR_Lock(ServerStateCVLock);
+ ServerState = state;
+ PR_NotifyCondVar(ServerStateCV);
+
+ if (debug_mode) {
+ DPRINTF("\t%s changed state to %d\n", waiter, state);
+ }
+
+ PR_Unlock(ServerStateCVLock);
+}
+
+int
+WaitServerState(char *waiter, PRInt32 state)
+{
+ PRInt32 rv;
+
+ PR_Lock(ServerStateCVLock);
+
+ if (debug_mode) {
+ DPRINTF("\t%s waiting for state %d\n", waiter, state);
+ }
+
+ while(!(ServerState & state)) {
+ PR_WaitCondVar(ServerStateCV, PR_INTERVAL_NO_TIMEOUT);
+ }
+ rv = ServerState;
+
+ if (debug_mode) DPRINTF("\t%s resuming from wait for state %d; state now %d\n",
+ waiter, state, ServerState);
+ PR_Unlock(ServerStateCVLock);
+
+ return rv;
+}
+
+/* --- Server Functions ------------------------------------------- */
+
+PRLock *workerThreadsLock;
+PRInt32 workerThreads;
+PRInt32 workerThreadsBusy;
+
+void
+WorkerThreadFunc(void *_listenSock)
+{
+ PRFileDesc *listenSock = (PRFileDesc *)_listenSock;
+ PRInt32 bytesRead;
+ PRInt32 bytesWritten;
+ char *dataBuf;
+ char *sendBuf;
+
+ if (debug_mode) DPRINTF("\tServer buffer is %d bytes; %d data, %d netaddrs\n",
+ _client_data+(2*sizeof(PRNetAddr))+32, _client_data, (2*sizeof(PRNetAddr))+32);
+ dataBuf = (char *)PR_MALLOC(_client_data + 2*sizeof(PRNetAddr) + 32);
+ if (!dataBuf)
+ if (debug_mode) {
+ printf("\tServer could not malloc space!?\n");
+ }
+ sendBuf = (char *)PR_MALLOC(_server_data *sizeof(char));
+ if (!sendBuf)
+ if (debug_mode) {
+ printf("\tServer could not malloc space!?\n");
+ }
+
+ if (debug_mode) {
+ DPRINTF("\tServer worker thread running\n");
+ }
+
+ while(1) {
+ PRInt32 bytesToRead = _client_data;
+ PRInt32 bytesToWrite = _server_data;
+ PRFileDesc *newSock;
+ PRNetAddr *rAddr;
+ PRInt32 loops = 0;
+
+ loops++;
+
+ if (debug_mode) {
+ DPRINTF("\tServer thread going into accept\n");
+ }
+
+ bytesRead = PR_AcceptRead(listenSock,
+ &newSock,
+ &rAddr,
+ dataBuf,
+ bytesToRead,
+ PR_INTERVAL_NO_TIMEOUT);
+
+ if (bytesRead < 0) {
+ if (debug_mode) {
+ printf("\tServer error in accept (%d)\n", bytesRead);
+ }
+ continue;
+ }
+
+ if (debug_mode) {
+ DPRINTF("\tServer accepted connection (%d bytes)\n", bytesRead);
+ }
+
+ PR_AtomicIncrement(&workerThreadsBusy);
+ if (workerThreadsBusy == workerThreads) {
+
+ PR_Lock(workerThreadsLock);
+ if (workerThreadsBusy == workerThreads) {
+ PRThread *WorkerThread;
+
+ WorkerThread = PR_CreateThread(
+ PR_SYSTEM_THREAD,
+ WorkerThreadFunc,
+ listenSock,
+ PR_PRIORITY_NORMAL,
+ ServerScope,
+ PR_UNJOINABLE_THREAD,
+ THREAD_STACKSIZE);
+
+ if (!WorkerThread) {
+ if (debug_mode) {
+ printf("Error creating client thread %d\n", workerThreads);
+ }
+ } else {
+ PR_AtomicIncrement(&workerThreads);
+ if (debug_mode) {
+ DPRINTF("\tServer creates worker (%d)\n", workerThreads);
+ }
+ }
+ }
+ PR_Unlock(workerThreadsLock);
+ }
+
+ bytesToRead -= bytesRead;
+ while (bytesToRead) {
+ bytesRead = PR_Recv(newSock,
+ dataBuf,
+ bytesToRead,
+ 0,
+ PR_INTERVAL_NO_TIMEOUT);
+ if (bytesRead < 0) {
+ if (debug_mode) {
+ printf("\tServer error receiving data (%d)\n", bytesRead);
+ }
+ continue;
+ }
+ if (debug_mode) {
+ DPRINTF("\tServer received %d bytes\n", bytesRead);
+ }
+ }
+
+ bytesWritten = PR_Send(newSock,
+ sendBuf,
+ bytesToWrite,
+ 0,
+ PR_INTERVAL_NO_TIMEOUT);
+ if (bytesWritten != _server_data) {
+ if (debug_mode) printf("\tError sending data to client (%d, %d)\n",
+ bytesWritten, PR_GetOSError());
+ } else {
+ if (debug_mode) {
+ DPRINTF("\tServer sent %d bytes\n", bytesWritten);
+ }
+ }
+
+ PR_Close(newSock);
+ PR_AtomicDecrement(&workerThreadsBusy);
+ }
+}
+
+PRFileDesc *
+ServerSetup(void)
+{
+ PRFileDesc *listenSocket;
+ PRSocketOptionData sockOpt;
+ PRNetAddr serverAddr;
+ PRThread *WorkerThread;
+
+ if ( (listenSocket = PR_NewTCPSocket()) == NULL) {
+ if (debug_mode) {
+ printf("\tServer error creating listen socket\n");
+ }
+ else {
+ failed_already=1;
+ }
+ return NULL;
+ }
+
+ sockOpt.option = PR_SockOpt_Reuseaddr;
+ sockOpt.value.reuse_addr = PR_TRUE;
+ if ( PR_SetSocketOption(listenSocket, &sockOpt) == PR_FAILURE) {
+ if (debug_mode) printf("\tServer error setting socket option: OS error %d\n",
+ PR_GetOSError());
+ else {
+ failed_already=1;
+ }
+ PR_Close(listenSocket);
+ return NULL;
+ }
+
+ memset(&serverAddr, 0, sizeof(PRNetAddr));
+ serverAddr.inet.family = PR_AF_INET;
+ serverAddr.inet.port = PR_htons(PORT);
+ serverAddr.inet.ip = PR_htonl(PR_INADDR_ANY);
+
+ if ( PR_Bind(listenSocket, &serverAddr) == PR_FAILURE) {
+ if (debug_mode) printf("\tServer error binding to server address: OS error %d\n",
+ PR_GetOSError());
+ else {
+ failed_already=1;
+ }
+ PR_Close(listenSocket);
+ return NULL;
+ }
+
+ if ( PR_Listen(listenSocket, 128) == PR_FAILURE) {
+ if (debug_mode) {
+ printf("\tServer error listening to server socket\n");
+ }
+ else {
+ failed_already=1;
+ }
+ PR_Close(listenSocket);
+
+ return NULL;
+ }
+
+ /* Create Clients */
+ workerThreads = 0;
+ workerThreadsBusy = 0;
+
+ workerThreadsLock = PR_NewLock();
+
+ WorkerThread = PR_CreateThread(
+ PR_SYSTEM_THREAD,
+ WorkerThreadFunc,
+ listenSocket,
+ PR_PRIORITY_NORMAL,
+ ServerScope,
+ PR_UNJOINABLE_THREAD,
+ THREAD_STACKSIZE);
+
+ if (!WorkerThread) {
+ if (debug_mode) {
+ printf("error creating working thread\n");
+ }
+ PR_Close(listenSocket);
+ return NULL;
+ }
+ PR_AtomicIncrement(&workerThreads);
+ if (debug_mode) {
+ DPRINTF("\tServer created primordial worker thread\n");
+ }
+
+ return listenSocket;
+}
+
+/* The main server loop */
+void
+ServerThreadFunc(void *unused)
+{
+ PRFileDesc *listenSocket;
+
+ /* Do setup */
+ listenSocket = ServerSetup();
+
+ if (!listenSocket) {
+ SetServerState(SERVER, SERVER_STATE_DEAD);
+ } else {
+
+ if (debug_mode) {
+ DPRINTF("\tServer up\n");
+ }
+
+ /* Tell clients they can start now. */
+ SetServerState(SERVER, SERVER_STATE_READY);
+
+ /* Now wait for server death signal */
+ WaitServerState(SERVER, SERVER_STATE_DYING);
+
+ /* Cleanup */
+ SetServerState(SERVER, SERVER_STATE_DEAD);
+ }
+}
+
+/* --- Client Functions ------------------------------------------- */
+
+PRInt32 numRequests;
+PRInt32 numClients;
+PRMonitor *clientMonitor;
+
+void
+ClientThreadFunc(void *unused)
+{
+ PRNetAddr serverAddr;
+ PRFileDesc *clientSocket;
+ char *sendBuf;
+ char *recvBuf;
+ PRInt32 rv;
+ PRInt32 bytesNeeded;
+
+ sendBuf = (char *)PR_MALLOC(_client_data * sizeof(char));
+ if (!sendBuf)
+ if (debug_mode) {
+ printf("\tClient could not malloc space!?\n");
+ }
+ recvBuf = (char *)PR_MALLOC(_server_data * sizeof(char));
+ if (!recvBuf)
+ if (debug_mode) {
+ printf("\tClient could not malloc space!?\n");
+ }
+
+ memset(&serverAddr, 0, sizeof(PRNetAddr));
+ serverAddr.inet.family = PR_AF_INET;
+ serverAddr.inet.port = PR_htons(PORT);
+ serverAddr.inet.ip = PR_htonl(PR_INADDR_LOOPBACK);
+
+ while(numRequests > 0) {
+
+ if ( (numRequests % 10) == 0 )
+ if (debug_mode) {
+ printf(".");
+ }
+ if (debug_mode) {
+ DPRINTF("\tClient starting request %d\n", numRequests);
+ }
+
+ clientSocket = PR_NewTCPSocket();
+ if (!clientSocket) {
+ if (debug_mode) printf("Client error creating socket: OS error %d\n",
+ PR_GetOSError());
+ continue;
+ }
+
+ if (debug_mode) {
+ DPRINTF("\tClient connecting\n");
+ }
+
+ rv = PR_Connect(clientSocket,
+ &serverAddr,
+ PR_INTERVAL_NO_TIMEOUT);
+ if (!clientSocket) {
+ if (debug_mode) {
+ printf("\tClient error connecting\n");
+ }
+ continue;
+ }
+
+ if (debug_mode) {
+ DPRINTF("\tClient connected\n");
+ }
+
+ rv = PR_Send(clientSocket,
+ sendBuf,
+ _client_data,
+ 0,
+ PR_INTERVAL_NO_TIMEOUT);
+ if (rv != _client_data) {
+ if (debug_mode) {
+ printf("Client error sending data (%d)\n", rv);
+ }
+ PR_Close(clientSocket);
+ continue;
+ }
+
+ if (debug_mode) {
+ DPRINTF("\tClient sent %d bytes\n", rv);
+ }
+
+ bytesNeeded = _server_data;
+ while(bytesNeeded) {
+ rv = PR_Recv(clientSocket,
+ recvBuf,
+ bytesNeeded,
+ 0,
+ PR_INTERVAL_NO_TIMEOUT);
+ if (rv <= 0) {
+ if (debug_mode) printf("Client error receiving data (%d) (%d/%d)\n",
+ rv, (_server_data - bytesNeeded), _server_data);
+ break;
+ }
+ if (debug_mode) {
+ DPRINTF("\tClient received %d bytes; need %d more\n", rv, bytesNeeded - rv);
+ }
+ bytesNeeded -= rv;
+ }
+
+ PR_Close(clientSocket);
+
+ PR_AtomicDecrement(&numRequests);
+ }
+
+ PR_EnterMonitor(clientMonitor);
+ --numClients;
+ PR_Notify(clientMonitor);
+ PR_ExitMonitor(clientMonitor);
+
+ PR_DELETE(sendBuf);
+ PR_DELETE(recvBuf);
+}
+
+void
+RunClients(void)
+{
+ PRInt32 index;
+
+ numRequests = _iterations;
+ numClients = _clients;
+ clientMonitor = PR_NewMonitor();
+
+ for (index=0; index<_clients; index++) {
+ PRThread *clientThread;
+
+
+ clientThread = PR_CreateThread(
+ PR_USER_THREAD,
+ ClientThreadFunc,
+ NULL,
+ PR_PRIORITY_NORMAL,
+ ClientScope,
+ PR_UNJOINABLE_THREAD,
+ THREAD_STACKSIZE);
+
+ if (!clientThread) {
+ if (debug_mode) {
+ printf("\terror creating client thread %d\n", index);
+ }
+ } else if (debug_mode) {
+ DPRINTF("\tMain created client %d/%d\n", index+1, _clients);
+ }
+
+ }
+
+ PR_EnterMonitor(clientMonitor);
+ while(numClients) {
+ PR_Wait(clientMonitor, PR_INTERVAL_NO_TIMEOUT);
+ }
+ PR_ExitMonitor(clientMonitor);
+}
+
+/* --- Main Function ---------------------------------------------- */
+
+static
+void do_work()
+{
+ PRThread *ServerThread;
+ PRInt32 state;
+
+ SetServerState(MAIN, SERVER_STATE_STARTUP);
+ ServerThread = PR_CreateThread(
+ PR_USER_THREAD,
+ ServerThreadFunc,
+ NULL,
+ PR_PRIORITY_NORMAL,
+ ServerScope,
+ PR_JOINABLE_THREAD,
+ THREAD_STACKSIZE);
+ if (!ServerThread) {
+ if (debug_mode) {
+ printf("error creating main server thread\n");
+ }
+ return;
+ }
+
+ /* Wait for server to be ready */
+ state = WaitServerState(MAIN, SERVER_STATE_READY|SERVER_STATE_DEAD);
+
+ if (!(state & SERVER_STATE_DEAD)) {
+ /* Run Test Clients */
+ RunClients();
+
+ /* Send death signal to server */
+ SetServerState(MAIN, SERVER_STATE_DYING);
+ }
+
+ PR_JoinThread(ServerThread);
+}
+
+static void do_workUU(void)
+{
+ ServerScope = PR_LOCAL_THREAD;
+ ClientScope = PR_LOCAL_THREAD;
+ do_work();
+}
+
+
+
+static void Measure(void (*func)(void), const char *msg)
+{
+ PRIntervalTime start, stop;
+ double d;
+
+ start = PR_IntervalNow();
+ (*func)();
+ stop = PR_IntervalNow();
+
+ d = (double)PR_IntervalToMicroseconds(stop - start);
+
+ if (debug_mode) {
+ printf("\n%40s: %6.2f usec\n", msg, d / _iterations);
+ }
+}
+
+
+int main(int argc, char **argv)
+{
+ /* The command line argument: -d is used to determine if the test is being run
+ in debug mode. The regress tool requires only one line output:PASS or FAIL.
+ All of the printfs associated with this test has been handled with a if (debug_mode)
+ test.
+ Usage: test_name -d
+ */
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "d:");
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 'd': /* debug mode */
+ debug_mode = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ /* main test */
+ if (debug_mode) {
+ printf("Enter number of iterations: \n");
+ scanf("%d", &_iterations);
+ printf("Enter number of clients : \n");
+ scanf("%d", &_clients);
+ printf("Enter size of client data : \n");
+ scanf("%d", &_client_data);
+ printf("Enter size of server data : \n");
+ scanf("%d", &_server_data);
+ }
+ else
+ {
+ _iterations = 7;
+ _clients = 7;
+ _client_data = 100;
+ _server_data = 100;
+ }
+
+ if (debug_mode) {
+ printf("\n\n%d iterations with %d client threads.\n",
+ _iterations, _clients);
+ printf("Sending %d bytes of client data and %d bytes of server data\n",
+ _client_data, _server_data);
+ }
+ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
+ PR_STDIO_INIT();
+
+ PR_SetThreadRecycleMode(64);
+
+ ServerStateCVLock = PR_NewLock();
+ ServerStateCV = PR_NewCondVar(ServerStateCVLock);
+
+ Measure(do_workUU, "server loop user/user");
+
+ PR_Cleanup();
+
+ if(failed_already) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+
+}
diff --git a/nsprpub/pr/tests/short_thread.c b/nsprpub/pr/tests/short_thread.c
new file mode 100644
index 0000000000..de069e8967
--- /dev/null
+++ b/nsprpub/pr/tests/short_thread.c
@@ -0,0 +1,60 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include <stdio.h>
+#include "nspr.h"
+#include "plgetopt.h"
+
+/*
+ * Create a thread that exits right away; useful for testing race conditions in thread
+ * creation
+ */
+
+int _debug_on = 0;
+#define DPRINTF(arg) if (_debug_on) printf arg
+
+static void housecleaning(void *cur_time);
+
+int main (int argc, char **argv)
+{
+ static PRIntervalTime thread_start_time;
+ static PRThread *housekeeping_tid = NULL;
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "d");
+
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 'd': /* debug mode */
+ _debug_on = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ if (( housekeeping_tid =
+ PR_CreateThread (PR_USER_THREAD, housecleaning, (void*)&thread_start_time,
+ PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD, 0))
+ == NULL ) {
+ fprintf(stderr,
+ "simple_test: Error - PR_CreateThread failed: (%ld, %ld)\n",
+ PR_GetError(), PR_GetOSError());
+ exit( 1 );
+ }
+ PR_Cleanup();
+ return(0);
+}
+
+static void
+housecleaning (void *cur_time)
+{
+ DPRINTF(("Child Thread exiting\n"));
+}
diff --git a/nsprpub/pr/tests/sigpipe.c b/nsprpub/pr/tests/sigpipe.c
new file mode 100644
index 0000000000..02ba9114f2
--- /dev/null
+++ b/nsprpub/pr/tests/sigpipe.c
@@ -0,0 +1,94 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ *************************************************************************
+ *
+ * Test: sigpipe.c
+ *
+ * Test the SIGPIPE handler in NSPR. This test applies to Unix only.
+ *
+ *************************************************************************
+ */
+
+#if !defined(XP_UNIX) && !defined(XP_OS2)
+
+int main(void)
+{
+ /* This test applies to Unix and OS/2. */
+ return 0;
+}
+
+#else /* XP_UNIX && OS/2 */
+
+#include "nspr.h"
+
+#ifdef XP_OS2
+#define INCL_DOSQUEUES
+#define INCL_DOSERRORS
+#include <os2.h>
+#endif
+
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+
+static void Test(void *arg)
+{
+#ifdef XP_OS2
+ HFILE pipefd[2];
+#else
+ int pipefd[2];
+#endif
+ int rv;
+ char c = '\0';
+
+#ifdef XP_OS2
+ if (DosCreatePipe(&pipefd[0], &pipefd[1], 4096) != 0) {
+#else
+ if (pipe(pipefd) == -1) {
+#endif
+ fprintf(stderr, "cannot create pipe: %d\n", errno);
+ exit(1);
+ }
+ close(pipefd[0]);
+
+ rv = write(pipefd[1], &c, 1);
+ if (rv != -1) {
+ fprintf(stderr, "write to broken pipe should have failed with EPIPE but returned %d\n", rv);
+ exit(1);
+ }
+ if (errno != EPIPE) {
+ fprintf(stderr, "write to broken pipe failed but with wrong errno: %d\n", errno);
+ exit(1);
+ }
+ close(pipefd[1]);
+ printf("write to broken pipe failed with EPIPE, as expected\n");
+}
+
+int main(int argc, char **argv)
+{
+ PRThread *thread;
+
+ /* This initializes NSPR. */
+ PR_SetError(0, 0);
+
+ thread = PR_CreateThread(PR_USER_THREAD, Test, NULL, PR_PRIORITY_NORMAL,
+ PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0);
+ if (thread == NULL) {
+ fprintf(stderr, "PR_CreateThread failed\n");
+ exit(1);
+ }
+ if (PR_JoinThread(thread) == PR_FAILURE) {
+ fprintf(stderr, "PR_JoinThread failed\n");
+ exit(1);
+ }
+ Test(NULL);
+
+ printf("PASSED\n");
+ return 0;
+}
+
+#endif /* XP_UNIX */
diff --git a/nsprpub/pr/tests/sleep.c b/nsprpub/pr/tests/sleep.c
new file mode 100644
index 0000000000..3e00acab01
--- /dev/null
+++ b/nsprpub/pr/tests/sleep.c
@@ -0,0 +1,105 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nspr.h"
+
+#if defined(XP_UNIX) || defined(XP_OS2)
+
+#include <stdio.h>
+
+#ifndef XP_OS2
+#include <unistd.h>
+#endif
+#include <sys/time.h>
+
+#if defined(HAVE_SVID_GETTOD)
+#define GTOD(_a) gettimeofday(_a)
+#else
+#define GTOD(_a) gettimeofday((_a), NULL)
+#endif
+
+static PRIntn rv = 0;
+
+static void Other(void *unused)
+{
+ PRIntn didit = 0;
+ while (PR_SUCCESS == PR_Sleep(PR_MillisecondsToInterval(250)))
+ {
+ fprintf(stderr, ".");
+ didit += 1;
+ }
+ if (didit < 5) {
+ rv = 1;
+ }
+}
+
+int main(int argc, char **argv)
+{
+ PRUint32 elapsed;
+ PRThread *thread;
+ struct timeval timein, timeout;
+ PRInt32 onePercent = 3000000UL / 100UL;
+
+ fprintf (stderr, "First sleep will sleep 3 seconds.\n");
+ fprintf (stderr, " sleep 1 begin\n");
+ (void)GTOD(&timein);
+ sleep (3);
+ (void)GTOD(&timeout);
+ fprintf (stderr, " sleep 1 end\n");
+ elapsed = 1000000UL * (timeout.tv_sec - timein.tv_sec);
+ elapsed += (timeout.tv_usec - timein.tv_usec);
+ fprintf(stderr, "elapsed %u usecs\n", elapsed);
+ if (labs(elapsed - 3000000UL) > onePercent) {
+ rv = 1;
+ }
+
+ PR_Init (PR_USER_THREAD, PR_PRIORITY_NORMAL, 100);
+ PR_STDIO_INIT();
+
+ fprintf (stderr, "Second sleep should do the same (does it?).\n");
+ fprintf (stderr, " sleep 2 begin\n");
+ (void)GTOD(&timein);
+ sleep (3);
+ (void)GTOD(&timeout);
+ fprintf (stderr, " sleep 2 end\n");
+ elapsed = 1000000UL * (timeout.tv_sec - timein.tv_sec);
+ elapsed += (timeout.tv_usec - timein.tv_usec);
+ fprintf(stderr, "elapsed %u usecs\n", elapsed);
+ if (labs(elapsed - 3000000UL) > onePercent) {
+ rv = 1;
+ }
+
+ fprintf (stderr, "What happens to other threads?\n");
+ fprintf (stderr, "You should see dots every quarter second.\n");
+ fprintf (stderr, "If you don't, you're probably running on classic NSPR.\n");
+ thread = PR_CreateThread(
+ PR_USER_THREAD, Other, NULL, PR_PRIORITY_NORMAL,
+ PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0);
+ fprintf (stderr, " sleep 2 begin\n");
+ (void)GTOD(&timein);
+ sleep (3);
+ (void)GTOD(&timeout);
+ fprintf (stderr, " sleep 2 end\n");
+ PR_Interrupt(thread);
+ PR_JoinThread(thread);
+ elapsed = 1000000UL * (timeout.tv_sec - timein.tv_sec);
+ elapsed += (timeout.tv_usec - timein.tv_usec);
+ fprintf(stderr, "elapsed %u usecs\n", elapsed);
+ if (labs(elapsed - 3000000UL) > onePercent) {
+ rv = 1;
+ }
+ fprintf(stderr, "%s\n", (0 == rv) ? "PASSED" : "FAILED");
+ return rv;
+}
+
+#else /* defined(XP_UNIX) */
+
+PRIntn main()
+{
+ return 2;
+}
+
+#endif /* defined(XP_UNIX) */
+
diff --git a/nsprpub/pr/tests/socket.c b/nsprpub/pr/tests/socket.c
new file mode 100644
index 0000000000..232898f69e
--- /dev/null
+++ b/nsprpub/pr/tests/socket.c
@@ -0,0 +1,2286 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/***********************************************************************
+**
+** Name: socket.c
+**
+** Description: Test socket functionality.
+**
+** Modification History:
+*/
+#include "primpl.h"
+
+#include "plgetopt.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#ifdef XP_UNIX
+#include <sys/mman.h>
+#endif
+#if defined(_PR_PTHREADS)
+#include <pthread.h>
+#endif
+
+#ifdef WIN32
+#include <process.h>
+#endif
+
+static int _debug_on = 0;
+static int test_cancelio = 0;
+
+#include "obsolete/prsem.h"
+
+#ifdef XP_PC
+#define mode_t int
+#endif
+
+#define DPRINTF(arg) if (_debug_on) printf arg
+
+#ifdef XP_PC
+char *TEST_DIR = "prdir";
+char *SMALL_FILE_NAME = "prsmallf";
+char *LARGE_FILE_NAME = "prlargef";
+#else
+char *TEST_DIR = "./tmp-prsocket_test_dir";
+char *SMALL_FILE_NAME = "./tmp-prsocket_test_dir/small_file";
+char *LARGE_FILE_NAME = "./tmp-prsocket_test_dir/large_file";
+#endif
+#define SMALL_FILE_SIZE (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_OFFSET_4 PR_GetPageSize()
+#define LARGE_FILE_LEN_4 769
+#define LARGE_FILE_HEADER_SIZE (512)
+#define LARGE_FILE_TRAILER_SIZE (64)
+
+#define BUF_DATA_SIZE (2 * 1024)
+#define TCP_MESG_SIZE 1024
+/*
+ * set UDP datagram size small enough that datagrams sent to a port on the
+ * local host will not be lost
+ */
+#define UDP_DGRAM_SIZE 128
+#define NUM_TCP_CLIENTS 5 /* for a listen queue depth of 5 */
+#define NUM_UDP_CLIENTS 10
+
+#define NUM_TRANSMITFILE_CLIENTS 4
+
+#define NUM_TCP_CONNECTIONS_PER_CLIENT 5
+#define NUM_TCP_MESGS_PER_CONNECTION 10
+#define NUM_UDP_DATAGRAMS_PER_CLIENT 5
+#define TCP_SERVER_PORT 10000
+#define UDP_SERVER_PORT TCP_SERVER_PORT
+#define SERVER_MAX_BIND_COUNT 100
+
+#ifdef WINCE
+#define perror(s)
+#endif
+
+static PRInt32 num_tcp_clients = NUM_TCP_CLIENTS;
+static PRInt32 num_udp_clients = NUM_UDP_CLIENTS;
+static PRInt32 num_transmitfile_clients = NUM_TRANSMITFILE_CLIENTS;
+static PRInt32 num_tcp_connections_per_client = NUM_TCP_CONNECTIONS_PER_CLIENT;
+static PRInt32 tcp_mesg_size = TCP_MESG_SIZE;
+static PRInt32 num_tcp_mesgs_per_connection = NUM_TCP_MESGS_PER_CONNECTION;
+static PRInt32 num_udp_datagrams_per_client = NUM_UDP_DATAGRAMS_PER_CLIENT;
+static PRInt32 udp_datagram_size = UDP_DGRAM_SIZE;
+
+static PRInt32 thread_count;
+PRUint16 server_domain = PR_AF_INET, client_domain = PR_AF_INET;
+
+/* an I/O layer that uses the emulated senfile method */
+static PRDescIdentity emuSendFileIdentity;
+static PRIOMethods emuSendFileMethods;
+
+int failed_already=0;
+typedef struct buffer {
+ char data[BUF_DATA_SIZE];
+} buffer;
+
+PRNetAddr tcp_server_addr, udp_server_addr;
+
+typedef struct Serve_Client_Param {
+ PRFileDesc *sockfd; /* socket to read from/write to */
+ PRInt32 datalen; /* bytes of data transfered in each read/write */
+} Serve_Client_Param;
+
+typedef struct Server_Param {
+ PRSemaphore *addr_sem; /* sem to post on, after setting up the address */
+ PRMonitor *exit_mon; /* monitor to signal on exit */
+ PRInt32 *exit_counter; /* counter to decrement, before exit */
+ PRInt32 datalen; /* bytes of data transfered in each read/write */
+} Server_Param;
+
+
+typedef struct Client_Param {
+ PRNetAddr server_addr;
+ PRMonitor *exit_mon; /* monitor to signal on exit */
+ PRInt32 *exit_counter; /* counter to decrement, before exit */
+ PRInt32 datalen;
+ PRInt32 udp_connect; /* if set clients connect udp sockets */
+} Client_Param;
+
+/* the sendfile method in emuSendFileMethods */
+static PRInt32 PR_CALLBACK
+emu_SendFile(PRFileDesc *sd, PRSendFileData *sfd,
+ PRTransmitFileFlags flags, PRIntervalTime timeout)
+{
+ return PR_EmulateSendFile(sd, sfd, flags, timeout);
+}
+
+/* the transmitfile method in emuSendFileMethods */
+static PRInt32 PR_CALLBACK
+emu_TransmitFile(PRFileDesc *sd, PRFileDesc *fd, const void *headers,
+ PRInt32 hlen, PRTransmitFileFlags flags, PRIntervalTime timeout)
+{
+ PRSendFileData sfd;
+
+ sfd.fd = fd;
+ sfd.file_offset = 0;
+ sfd.file_nbytes = 0;
+ sfd.header = headers;
+ sfd.hlen = hlen;
+ sfd.trailer = NULL;
+ sfd.tlen = 0;
+ return emu_SendFile(sd, &sfd, flags, timeout);
+}
+
+/*
+ * readn
+ * read data from sockfd into buf
+ */
+static PRInt32
+readn(PRFileDesc *sockfd, char *buf, int len)
+{
+ int rem;
+ int bytes;
+ int offset = 0;
+ int err;
+ 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,
+ timeout);
+ DPRINTF(("thread = 0x%lx: returning from PR_Recv, bytes = %d\n",
+ PR_GetCurrentThread(), bytes));
+ 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;
+}
+
+/*
+ * writen
+ * write data from buf to sockfd
+ */
+static PRInt32
+writen(PRFileDesc *sockfd, char *buf, int len)
+{
+ int rem;
+ int bytes;
+ int offset = 0;
+
+ for (rem=len; rem; offset += bytes, rem -= bytes) {
+ DPRINTF(("thread = 0x%lx: calling PR_Send, bytes = %d\n",
+ PR_GetCurrentThread(), rem));
+ bytes = PR_Send(sockfd, buf + offset, rem, 0,
+ PR_INTERVAL_NO_TIMEOUT);
+ DPRINTF(("thread = 0x%lx: returning from PR_Send, bytes = %d\n",
+ PR_GetCurrentThread(), bytes));
+ if (bytes <= 0) {
+ return -1;
+ }
+ }
+ return len;
+}
+
+/*
+ * Serve_Client
+ * Thread, started by the server, for serving a client connection.
+ * Reads data from socket and writes it back, unmodified, and
+ * closes the socket
+ */
+static void PR_CALLBACK
+Serve_Client(void *arg)
+{
+ Serve_Client_Param *scp = (Serve_Client_Param *) arg;
+ PRFileDesc *sockfd;
+ buffer *in_buf;
+ PRInt32 bytes, j;
+
+ sockfd = scp->sockfd;
+ bytes = scp->datalen;
+ in_buf = PR_NEW(buffer);
+ if (in_buf == NULL) {
+ fprintf(stderr,"prsocket_test: failed to alloc buffer struct\n");
+ failed_already=1;
+ goto exit;
+ }
+
+
+ for (j = 0; j < num_tcp_mesgs_per_connection; j++) {
+ /*
+ * Read data from client and send it back to the client unmodified
+ */
+ if (readn(sockfd, in_buf->data, bytes) < bytes) {
+ fprintf(stderr,"prsocket_test: ERROR - Serve_Client:readn\n");
+ failed_already=1;
+ goto exit;
+ }
+ /* Shutdown only RCV will cause error on Symbian OS */
+ /*
+ * shutdown reads, after the last read
+ */
+ if (j == num_tcp_mesgs_per_connection - 1)
+ if (PR_Shutdown(sockfd, PR_SHUTDOWN_RCV) < 0) {
+ fprintf(stderr,"prsocket_test: ERROR - PR_Shutdown\n");
+ }
+ DPRINTF(("Serve_Client [0x%lx]: inbuf[0] = 0x%lx\n",PR_GetCurrentThread(),
+ (*((int *) in_buf->data))));
+ if (writen(sockfd, in_buf->data, bytes) < bytes) {
+ fprintf(stderr,"prsocket_test: ERROR - Serve_Client:writen\n");
+ failed_already=1;
+ goto exit;
+ }
+ }
+ /*
+ * shutdown reads and writes
+ */
+ if (PR_Shutdown(sockfd, PR_SHUTDOWN_BOTH) < 0) {
+ fprintf(stderr,"prsocket_test: ERROR - PR_Shutdown\n");
+ failed_already=1;
+ }
+
+exit:
+ PR_Close(sockfd);
+ if (in_buf) {
+ PR_DELETE(in_buf);
+ }
+}
+
+PRThread* create_new_thread(PRThreadType type,
+ void (*start)(void *arg),
+ void *arg,
+ PRThreadPriority priority,
+ PRThreadScope scope,
+ PRThreadState state,
+ PRUint32 stackSize, PRInt32 index)
+{
+ PRInt32 native_thread = 0;
+
+ PR_ASSERT(state == PR_UNJOINABLE_THREAD);
+#if defined(_PR_PTHREADS) || defined(WIN32)
+ switch(index % 4) {
+ case 0:
+ scope = (PR_LOCAL_THREAD);
+ break;
+ case 1:
+ scope = (PR_GLOBAL_THREAD);
+ break;
+ case 2:
+ scope = (PR_GLOBAL_BOUND_THREAD);
+ break;
+ case 3:
+ native_thread = 1;
+ break;
+ default:
+ PR_NOT_REACHED("Invalid scope");
+ break;
+ }
+ if (native_thread) {
+#if defined(_PR_PTHREADS)
+ pthread_t tid;
+ if (!pthread_create(&tid, NULL, (void * (*)(void *)) start, arg)) {
+ return((PRThread *) tid);
+ }
+ else {
+ return (NULL);
+ }
+#else
+ HANDLE thandle;
+ unsigned tid;
+
+ thandle = (HANDLE) _beginthreadex(
+ NULL,
+ stackSize,
+ (unsigned (__stdcall *)(void *))start,
+ arg,
+ STACK_SIZE_PARAM_IS_A_RESERVATION,
+ &tid);
+ return((PRThread *) thandle);
+#endif
+ } else {
+ return(PR_CreateThread(type,start,arg,priority,scope,state,stackSize));
+ }
+#else
+ return(PR_CreateThread(type,start,arg,priority,scope,state,stackSize));
+#endif
+}
+
+/*
+ * TCP Server
+ * Server Thread
+ * Bind an address to a socket and listen for incoming connections
+ * Start a Serve_Client thread for each incoming connection.
+ */
+static void PR_CALLBACK
+TCP_Server(void *arg)
+{
+ PRThread *t;
+ Server_Param *sp = (Server_Param *) arg;
+ Serve_Client_Param *scp;
+ PRFileDesc *sockfd, *newsockfd;
+ PRNetAddr netaddr;
+ PRInt32 i;
+ /*
+ * Create a tcp socket
+ */
+ if ((sockfd = PR_OpenTCPSocket(server_domain)) == NULL) {
+ fprintf(stderr,"prsocket_test: PR_NewTCPSocket failed\n");
+ goto exit;
+ }
+ memset(&netaddr, 0, sizeof(netaddr));
+
+ if (PR_SetNetAddr(PR_IpAddrAny, server_domain, TCP_SERVER_PORT,
+ &netaddr) == PR_FAILURE) {
+ fprintf(stderr,"prsocket_test: PR_SetNetAddr failed\n");
+ goto exit;
+ }
+ /*
+ * try a few times to bind server's address, if addresses are in
+ * use
+ */
+ i = 0;
+
+ while (PR_Bind(sockfd, &netaddr) < 0) {
+ if (PR_GetError() == PR_ADDRESS_IN_USE_ERROR) {
+ netaddr.inet.port += 2;
+ if (i++ < SERVER_MAX_BIND_COUNT) {
+ continue;
+ }
+ }
+ fprintf(stderr,"prsocket_test: ERROR - PR_Bind failed\n");
+ perror("PR_Bind");
+ failed_already=1;
+ goto exit;
+ }
+
+ if (PR_Listen(sockfd, 32) < 0) {
+ fprintf(stderr,"prsocket_test: ERROR - PR_Listen failed\n");
+ failed_already=1;
+ goto exit;
+ }
+
+ if (PR_GetSockName(sockfd, &netaddr) < 0) {
+ fprintf(stderr,"prsocket_test: ERROR - PR_GetSockName failed\n");
+ failed_already=1;
+ goto exit;
+ }
+
+ DPRINTF(("TCP_Server: PR_BIND netaddr.inet.ip = 0x%lx, netaddr.inet.port = %d\n",
+ netaddr.inet.ip, netaddr.inet.port));
+ if (PR_SetNetAddr(PR_IpAddrLoopback, client_domain,
+ PR_ntohs(PR_NetAddrInetPort(&netaddr)),
+ &tcp_server_addr) == PR_FAILURE) {
+ fprintf(stderr,"prsocket_test: PR_SetNetAddr failed\n");
+ goto exit;
+ }
+ if ((client_domain == PR_AF_INET6) && (server_domain == PR_AF_INET))
+ PR_ConvertIPv4AddrToIPv6(PR_htonl(INADDR_LOOPBACK),
+ &tcp_server_addr.ipv6.ip);
+
+ /*
+ * Wake up parent thread because server address is bound and made
+ * available in the global variable 'tcp_server_addr'
+ */
+ PR_PostSem(sp->addr_sem);
+
+ for (i = 0; i < (num_tcp_clients * num_tcp_connections_per_client); i++) {
+ /* test both null and non-null 'addr' argument to PR_Accept */
+ PRNetAddr *addrp = (i%2 ? &netaddr: NULL);
+
+ DPRINTF(("TCP_Server: Accepting connection\n"));
+ if ((newsockfd = PR_Accept(sockfd, addrp,
+ PR_INTERVAL_NO_TIMEOUT)) == NULL) {
+ fprintf(stderr,"prsocket_test: ERROR - PR_Accept failed\n");
+ goto exit;
+ }
+ DPRINTF(("TCP_Server: Accepted connection\n"));
+ scp = PR_NEW(Serve_Client_Param);
+ if (scp == NULL) {
+ fprintf(stderr,"prsocket_test: PR_NEW failed\n");
+ goto exit;
+ }
+
+ /*
+ * Start a Serve_Client thread for each incoming connection
+ */
+ scp->sockfd = newsockfd;
+ scp->datalen = sp->datalen;
+
+ t = create_new_thread(PR_USER_THREAD,
+ Serve_Client, (void *)scp,
+ PR_PRIORITY_NORMAL,
+ PR_LOCAL_THREAD,
+ PR_UNJOINABLE_THREAD,
+ 0, i);
+ if (t == NULL) {
+ fprintf(stderr,"prsocket_test: PR_CreateThread failed\n");
+ failed_already=1;
+ goto exit;
+ }
+ DPRINTF(("TCP_Server: Created Serve_Client = 0x%lx\n", t));
+ }
+
+exit:
+ if (sockfd) {
+ PR_Close(sockfd);
+ }
+
+ /*
+ * Decrement exit_counter and notify parent thread
+ */
+
+ PR_EnterMonitor(sp->exit_mon);
+ --(*sp->exit_counter);
+ PR_Notify(sp->exit_mon);
+ PR_ExitMonitor(sp->exit_mon);
+ DPRINTF(("TCP_Server [0x%lx] exiting\n", PR_GetCurrentThread()));
+}
+
+/*
+ * UDP Server
+ * Server Thread
+ * Bind an address to a socket, read data from clients and send data
+ * back to clients
+ */
+static void PR_CALLBACK
+UDP_Server(void *arg)
+{
+ Server_Param *sp = (Server_Param *) arg;
+ PRFileDesc *sockfd;
+ buffer *in_buf;
+ PRNetAddr netaddr;
+ PRInt32 bytes, i, rv = 0;
+
+
+ bytes = sp->datalen;
+ /*
+ * Create a udp socket
+ */
+ if ((sockfd = PR_OpenUDPSocket(server_domain)) == NULL) {
+ fprintf(stderr,"prsocket_test: PR_NewUDPSocket failed\n");
+ failed_already=1;
+ return;
+ }
+ memset(&netaddr, 0, sizeof(netaddr));
+ if (PR_SetNetAddr(PR_IpAddrAny, server_domain, UDP_SERVER_PORT,
+ &netaddr) == PR_FAILURE) {
+ fprintf(stderr,"prsocket_test: PR_SetNetAddr failed\n");
+ failed_already=1;
+ return;
+ }
+ /*
+ * try a few times to bind server's address, if addresses are in
+ * use
+ */
+ i = 0;
+ while (PR_Bind(sockfd, &netaddr) < 0) {
+ if (PR_GetError() == PR_ADDRESS_IN_USE_ERROR) {
+ netaddr.inet.port += 2;
+ if (i++ < SERVER_MAX_BIND_COUNT) {
+ continue;
+ }
+ }
+ fprintf(stderr,"prsocket_test: ERROR - PR_Bind failed\n");
+ perror("PR_Bind");
+ failed_already=1;
+ return;
+ }
+
+ if (PR_GetSockName(sockfd, &netaddr) < 0) {
+ fprintf(stderr,"prsocket_test: ERROR - PR_GetSockName failed\n");
+ 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));
+ /*
+ * We can't use the IP address returned by PR_GetSockName in
+ * netaddr.inet.ip because netaddr.inet.ip is returned
+ * as 0 (= PR_INADDR_ANY).
+ */
+
+ if (PR_SetNetAddr(PR_IpAddrLoopback, client_domain,
+ PR_ntohs(PR_NetAddrInetPort(&netaddr)),
+ &udp_server_addr) == PR_FAILURE) {
+ fprintf(stderr,"prsocket_test: PR_SetNetAddr failed\n");
+ failed_already=1;
+ return;
+ }
+ if ((client_domain == PR_AF_INET6) && (server_domain == PR_AF_INET))
+ PR_ConvertIPv4AddrToIPv6(PR_htonl(INADDR_LOOPBACK),
+ &udp_server_addr.ipv6.ip);
+
+ /*
+ * Wake up parent thread because server address is bound and made
+ * available in the global variable 'udp_server_addr'
+ */
+ PR_PostSem(sp->addr_sem);
+
+ bytes = sp->datalen;
+ in_buf = PR_NEW(buffer);
+ if (in_buf == NULL) {
+ fprintf(stderr,"prsocket_test: failed to alloc buffer struct\n");
+ failed_already=1;
+ return;
+ }
+ /*
+ * Receive datagrams from clients and send them back, unmodified, to the
+ * clients
+ */
+ memset(&netaddr, 0, sizeof(netaddr));
+ for (i = 0; i < (num_udp_clients * num_udp_datagrams_per_client); i++) {
+ DPRINTF(("UDP_Server: calling PR_RecvFrom client - ip = 0x%lx, port = %d bytes = %d inbuf = 0x%lx, inbuf[0] = 0x%lx\n",
+ netaddr.inet.ip, netaddr.inet.port, bytes, in_buf->data,
+ in_buf->data[0]));
+
+ rv = PR_RecvFrom(sockfd, in_buf->data, bytes, 0, &netaddr,
+ PR_INTERVAL_NO_TIMEOUT);
+ DPRINTF(("UDP_Server: PR_RecvFrom client - ip = 0x%lx, port = %d bytes = %d inbuf = 0x%lx, inbuf[0] = 0x%lx\n",
+ netaddr.inet.ip, netaddr.inet.port, rv, in_buf->data,
+ in_buf->data[0]));
+ if (rv != bytes) {
+ return;
+ }
+ rv = PR_SendTo(sockfd, in_buf->data, bytes, 0, &netaddr,
+ PR_INTERVAL_NO_TIMEOUT);
+ if (rv != bytes) {
+ return;
+ }
+ }
+
+ PR_DELETE(in_buf);
+ PR_Close(sockfd);
+
+ /*
+ * Decrement exit_counter and notify parent thread
+ */
+ PR_EnterMonitor(sp->exit_mon);
+ --(*sp->exit_counter);
+ PR_Notify(sp->exit_mon);
+ PR_ExitMonitor(sp->exit_mon);
+ DPRINTF(("UDP_Server [0x%x] exiting\n", PR_GetCurrentThread()));
+}
+
+/*
+ * TCP_Client
+ * Client Thread
+ * Connect to the server at the address specified in the argument.
+ * Fill in a buffer, write data to server, read it back and check
+ * for data corruption.
+ * Close the socket for server connection
+ */
+static void PR_CALLBACK
+TCP_Client(void *arg)
+{
+ Client_Param *cp = (Client_Param *) arg;
+ PRFileDesc *sockfd;
+ buffer *in_buf, *out_buf;
+ union PRNetAddr netaddr;
+ PRInt32 bytes, i, j;
+
+
+ bytes = cp->datalen;
+ out_buf = PR_NEW(buffer);
+ if (out_buf == NULL) {
+ fprintf(stderr,"prsocket_test: failed to alloc buffer struct\n");
+ failed_already=1;
+ return;
+ }
+ in_buf = PR_NEW(buffer);
+ if (in_buf == NULL) {
+ fprintf(stderr,"prsocket_test: failed to alloc buffer struct\n");
+ failed_already=1;
+ return;
+ }
+ netaddr = cp->server_addr;
+
+ for (i = 0; i < num_tcp_connections_per_client; i++) {
+ if ((sockfd = PR_OpenTCPSocket(client_domain)) == 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, "PR_Connect failed: (%ld, %ld)\n",
+ PR_GetError(), PR_GetOSError());
+ failed_already=1;
+ return;
+ }
+ for (j = 0; j < num_tcp_mesgs_per_connection; j++) {
+ /*
+ * fill in random data
+ */
+ memset(out_buf->data, ((PRInt32) (&netaddr)) + i + j, bytes);
+ /*
+ * 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;
+ return;
+ }
+ DPRINTF(("TCP Client [0x%lx]: out_buf = 0x%lx out_buf[0] = 0x%lx\n",
+ PR_GetCurrentThread(), out_buf, (*((int *) out_buf->data))));
+ if (readn(sockfd, in_buf->data, bytes) < bytes) {
+ fprintf(stderr,"prsocket_test: ERROR - TCP_Client:readn\n");
+ failed_already=1;
+ return;
+ }
+ /*
+ * verify the data read
+ */
+ if (memcmp(in_buf->data, out_buf->data, bytes) != 0) {
+ fprintf(stderr,"prsocket_test: ERROR - data corruption\n");
+ failed_already=1;
+ return;
+ }
+ }
+ /*
+ * shutdown reads and writes
+ */
+ if (PR_Shutdown(sockfd, PR_SHUTDOWN_BOTH) < 0) {
+ fprintf(stderr,"prsocket_test: ERROR - PR_Shutdown\n");
+ failed_already=1;
+ }
+ PR_Close(sockfd);
+ }
+
+ PR_DELETE(out_buf);
+ PR_DELETE(in_buf);
+
+ /*
+ * Decrement exit_counter and notify parent thread
+ */
+
+ PR_EnterMonitor(cp->exit_mon);
+ --(*cp->exit_counter);
+ PR_Notify(cp->exit_mon);
+ PR_ExitMonitor(cp->exit_mon);
+ DPRINTF(("TCP_Client [0x%x] exiting\n", PR_GetCurrentThread()));
+}
+
+/*
+ * UDP_Client
+ * Client Thread
+ * Create a socket and bind an address
+ * Communicate with the server at the address specified in the argument.
+ * Fill in a buffer, write data to server, read it back and check
+ * for data corruption.
+ * Close the socket
+ */
+static void PR_CALLBACK
+UDP_Client(void *arg)
+{
+ Client_Param *cp = (Client_Param *) arg;
+ PRFileDesc *sockfd;
+ buffer *in_buf, *out_buf;
+ union PRNetAddr netaddr;
+ PRInt32 bytes, i, rv;
+
+
+ bytes = cp->datalen;
+ out_buf = PR_NEW(buffer);
+ if (out_buf == NULL) {
+ fprintf(stderr,"prsocket_test: failed to alloc buffer struct\n");
+ failed_already=1;
+ return;
+ }
+ in_buf = PR_NEW(buffer);
+ if (in_buf == NULL) {
+ fprintf(stderr,"prsocket_test: failed to alloc buffer struct\n");
+ failed_already=1;
+ return;
+ }
+ if ((sockfd = PR_OpenUDPSocket(client_domain)) == NULL) {
+ fprintf(stderr,"prsocket_test: PR_OpenUDPSocket failed\n");
+ failed_already=1;
+ return;
+ }
+
+ /*
+ * bind an address for the client, let the system chose the port
+ * number
+ */
+ memset(&netaddr, 0, sizeof(netaddr));
+ if (PR_SetNetAddr(PR_IpAddrAny, client_domain, 0,
+ &netaddr) == PR_FAILURE) {
+ fprintf(stderr,"prsocket_test: PR_SetNetAddr failed\n");
+ failed_already=1;
+ return;
+ }
+ if (PR_Bind(sockfd, &netaddr) < 0) {
+ fprintf(stderr,"prsocket_test: ERROR - PR_Bind failed\n");
+ perror("PR_Bind");
+ return;
+ }
+
+ if (PR_GetSockName(sockfd, &netaddr) < 0) {
+ fprintf(stderr,"prsocket_test: ERROR - PR_GetSockName failed\n");
+ failed_already=1;
+ return;
+ }
+
+ DPRINTF(("PR_Bind: UDP Client netaddr.inet.ip = 0x%lx, netaddr.inet.port = %d\n",
+ netaddr.inet.ip, netaddr.inet.port));
+
+ netaddr = cp->server_addr;
+
+ if (cp->udp_connect) {
+ if (PR_Connect(sockfd, &netaddr,PR_INTERVAL_NO_TIMEOUT) < 0) {
+ fprintf(stderr,"prsocket_test: PR_Connect failed\n");
+ failed_already=1;
+ return;
+ }
+ }
+
+ for (i = 0; i < num_udp_datagrams_per_client; i++) {
+ /*
+ * fill in random data
+ */
+ DPRINTF(("UDP_Client [0x%lx]: out_buf = 0x%lx bytes = 0x%lx\n",
+ PR_GetCurrentThread(), out_buf->data, bytes));
+ memset(out_buf->data, ((PRInt32) (&netaddr)) + i, bytes);
+ /*
+ * write to server
+ */
+ if (cp->udp_connect)
+ rv = PR_Send(sockfd, out_buf->data, bytes, 0,
+ PR_INTERVAL_NO_TIMEOUT);
+ else
+ rv = PR_SendTo(sockfd, out_buf->data, bytes, 0, &netaddr,
+ PR_INTERVAL_NO_TIMEOUT);
+ if (rv != bytes) {
+ return;
+ }
+ DPRINTF(("UDP_Client [0x%lx]: out_buf = 0x%lx out_buf[0] = 0x%lx\n",
+ PR_GetCurrentThread(), out_buf, (*((int *) out_buf->data))));
+ if (cp->udp_connect)
+ rv = PR_Recv(sockfd, in_buf->data, bytes, 0,
+ PR_INTERVAL_NO_TIMEOUT);
+ else
+ rv = PR_RecvFrom(sockfd, in_buf->data, bytes, 0, &netaddr,
+ PR_INTERVAL_NO_TIMEOUT);
+ if (rv != bytes) {
+ return;
+ }
+ DPRINTF(("UDP_Client [0x%lx]: in_buf = 0x%lx in_buf[0] = 0x%lx\n",
+ PR_GetCurrentThread(), in_buf, (*((int *) in_buf->data))));
+ /*
+ * verify the data read
+ */
+ if (memcmp(in_buf->data, out_buf->data, bytes) != 0) {
+ fprintf(stderr,"prsocket_test: ERROR - UDP data corruption\n");
+ failed_already=1;
+ return;
+ }
+ }
+ PR_Close(sockfd);
+
+ PR_DELETE(in_buf);
+ PR_DELETE(out_buf);
+
+ /*
+ * Decrement exit_counter and notify parent thread
+ */
+
+ PR_EnterMonitor(cp->exit_mon);
+ --(*cp->exit_counter);
+ PR_Notify(cp->exit_mon);
+ PR_ExitMonitor(cp->exit_mon);
+ PR_DELETE(cp);
+ DPRINTF(("UDP_Client [0x%x] exiting\n", PR_GetCurrentThread()));
+}
+
+/*
+ * TCP_Socket_Client_Server_Test - concurrent server test
+ *
+ * One server and several clients are started
+ * Each client connects to the server and sends a chunk of data
+ * For each connection, server starts another thread to read the data
+ * from the client and send it back to the client, unmodified.
+ * Each client checks that data received from server is same as the
+ * data it sent to the server.
+ *
+ */
+
+static PRInt32
+TCP_Socket_Client_Server_Test(void)
+{
+ int i;
+ PRThread *t;
+ PRSemaphore *server_sem;
+ Server_Param *sparamp;
+ Client_Param *cparamp;
+ PRMonitor *mon2;
+ PRInt32 datalen;
+
+
+ datalen = tcp_mesg_size;
+ thread_count = 0;
+ /*
+ * start the server thread
+ */
+ sparamp = PR_NEW(Server_Param);
+ if (sparamp == NULL) {
+ fprintf(stderr,"prsocket_test: PR_NEW failed\n");
+ failed_already=1;
+ return -1;
+ }
+ server_sem = PR_NewSem(0);
+ if (server_sem == NULL) {
+ fprintf(stderr,"prsocket_test: PR_NewSem failed\n");
+ failed_already=1;
+ return -1;
+ }
+ mon2 = PR_NewMonitor();
+ if (mon2 == NULL) {
+ fprintf(stderr,"prsocket_test: PR_NewMonitor failed\n");
+ failed_already=1;
+ return -1;
+ }
+ PR_EnterMonitor(mon2);
+
+ sparamp->addr_sem = server_sem;
+ sparamp->exit_mon = mon2;
+ sparamp->exit_counter = &thread_count;
+ sparamp->datalen = datalen;
+ t = PR_CreateThread(PR_USER_THREAD,
+ TCP_Server, (void *)sparamp,
+ PR_PRIORITY_NORMAL,
+ PR_LOCAL_THREAD,
+ PR_UNJOINABLE_THREAD,
+ 0);
+ if (t == NULL) {
+ fprintf(stderr,"prsocket_test: PR_CreateThread failed\n");
+ failed_already=1;
+ return -1;
+ }
+ DPRINTF(("Created TCP server = 0x%lx\n", t));
+ thread_count++;
+
+ /*
+ * wait till the server address is setup
+ */
+ PR_WaitSem(server_sem);
+
+ /*
+ * Now start a bunch of client threads
+ */
+
+ cparamp = PR_NEW(Client_Param);
+ if (cparamp == NULL) {
+ fprintf(stderr,"prsocket_test: PR_NEW failed\n");
+ failed_already=1;
+ return -1;
+ }
+ cparamp->server_addr = tcp_server_addr;
+ cparamp->exit_mon = mon2;
+ cparamp->exit_counter = &thread_count;
+ cparamp->datalen = datalen;
+ for (i = 0; i < num_tcp_clients; i++) {
+ t = create_new_thread(PR_USER_THREAD,
+ TCP_Client, (void *) cparamp,
+ PR_PRIORITY_NORMAL,
+ PR_LOCAL_THREAD,
+ PR_UNJOINABLE_THREAD,
+ 0, i);
+ if (t == NULL) {
+ fprintf(stderr,"prsocket_test: PR_CreateThread failed\n");
+ failed_already=1;
+ return -1;
+ }
+ DPRINTF(("Created TCP client = 0x%lx\n", t));
+ thread_count++;
+ }
+ /* Wait for server and client threads to exit */
+ while (thread_count) {
+ PR_Wait(mon2, PR_INTERVAL_NO_TIMEOUT);
+ DPRINTF(("TCP Server - thread_count = %d\n", thread_count));
+ }
+ PR_ExitMonitor(mon2);
+ printf("%30s","TCP_Socket_Client_Server_Test:");
+ printf("%2ld Server %2ld Clients %2ld connections_per_client\n",1l,
+ num_tcp_clients, num_tcp_connections_per_client);
+ printf("%30s %2ld messages_per_connection %4ld bytes_per_message\n",":",
+ num_tcp_mesgs_per_connection, tcp_mesg_size);
+
+ return 0;
+}
+
+/*
+ * UDP_Socket_Client_Server_Test - iterative server test
+ *
+ * One server and several clients are started
+ * Each client connects to the server and sends a chunk of data
+ * For each connection, server starts another thread to read the data
+ * from the client and send it back to the client, unmodified.
+ * Each client checks that data received from server is same as the
+ * data it sent to the server.
+ *
+ */
+
+static PRInt32
+UDP_Socket_Client_Server_Test(void)
+{
+ int i;
+ PRThread *t;
+ PRSemaphore *server_sem;
+ Server_Param *sparamp;
+ Client_Param *cparamp;
+ PRMonitor *mon2;
+ PRInt32 datalen;
+ PRInt32 udp_connect = 1;
+
+
+ datalen = udp_datagram_size;
+ thread_count = 0;
+ /*
+ * start the server thread
+ */
+ sparamp = PR_NEW(Server_Param);
+ if (sparamp == NULL) {
+ fprintf(stderr,"prsocket_test: PR_NEW failed\n");
+ failed_already=1;
+ return -1;
+ }
+ server_sem = PR_NewSem(0);
+ if (server_sem == NULL) {
+ fprintf(stderr,"prsocket_test: PR_NewSem failed\n");
+ failed_already=1;
+ return -1;
+ }
+ mon2 = PR_NewMonitor();
+ if (mon2 == NULL) {
+ fprintf(stderr,"prsocket_test: PR_NewMonitor failed\n");
+ failed_already=1;
+ return -1;
+ }
+ PR_EnterMonitor(mon2);
+
+ sparamp->addr_sem = server_sem;
+ sparamp->exit_mon = mon2;
+ sparamp->exit_counter = &thread_count;
+ sparamp->datalen = datalen;
+ DPRINTF(("Creating UDP server"));
+ t = PR_CreateThread(PR_USER_THREAD,
+ UDP_Server, (void *)sparamp,
+ PR_PRIORITY_NORMAL,
+ PR_LOCAL_THREAD,
+ PR_UNJOINABLE_THREAD,
+ 0);
+ if (t == NULL) {
+ fprintf(stderr,"prsocket_test: PR_CreateThread failed\n");
+ failed_already=1;
+ return -1;
+ }
+ thread_count++;
+
+ /*
+ * wait till the server address is setup
+ */
+ PR_WaitSem(server_sem);
+
+ /*
+ * Now start a bunch of client threads
+ */
+
+ for (i = 0; i < num_udp_clients; i++) {
+ cparamp = PR_NEW(Client_Param);
+ if (cparamp == NULL) {
+ fprintf(stderr,"prsocket_test: PR_NEW failed\n");
+ failed_already=1;
+ return -1;
+ }
+ cparamp->server_addr = udp_server_addr;
+ cparamp->exit_mon = mon2;
+ cparamp->exit_counter = &thread_count;
+ cparamp->datalen = datalen;
+ /*
+ * Cause every other client thread to connect udp sockets
+ */
+ cparamp->udp_connect = udp_connect;
+ if (udp_connect) {
+ udp_connect = 0;
+ }
+ else {
+ udp_connect = 1;
+ }
+ DPRINTF(("Creating UDP client %d\n", i));
+ t = PR_CreateThread(PR_USER_THREAD,
+ UDP_Client, (void *) cparamp,
+ PR_PRIORITY_NORMAL,
+ PR_LOCAL_THREAD,
+ PR_UNJOINABLE_THREAD,
+ 0);
+ if (t == NULL) {
+ fprintf(stderr,"prsocket_test: PR_CreateThread failed\n");
+ failed_already=1;
+ return -1;
+ }
+ thread_count++;
+ }
+ /* Wait for server and client threads to exit */
+ while (thread_count) {
+ PR_Wait(mon2, PR_INTERVAL_NO_TIMEOUT);
+ DPRINTF(("UDP Server - thread_count = %d\n", thread_count));
+ }
+ PR_ExitMonitor(mon2);
+ printf("%30s","UDP_Socket_Client_Server_Test: ");
+ printf("%2ld Server %2ld Clients\n",1l, num_udp_clients);
+ printf("%30s %2ld datagrams_per_client %4ld bytes_per_datagram\n",":",
+ num_udp_datagrams_per_client, udp_datagram_size);
+
+ return 0;
+}
+
+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
+ */
+static void
+TransmitFile_Client(void *arg)
+{
+ PRFileDesc *sockfd;
+ 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_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_FILE_HEADER_SIZE +
+ LARGE_FILE_TRAILER_SIZE);
+ if (large_buf == NULL) {
+ fprintf(stderr,"prsocket_test: failed to alloc buffer\n");
+ failed_already=1;
+ return;
+ }
+ netaddr.inet.family = cp->server_addr.inet.family;
+ netaddr.inet.port = cp->server_addr.inet.port;
+ netaddr.inet.ip = cp->server_addr.inet.ip;
+
+ if ((sockfd = PR_NewTCPSocket()) == NULL) {
+ fprintf(stderr,"prsocket_test: PR_NewTCPSocket failed\n");
+ failed_already=1;
+ return;
+ }
+
+ if (PR_Connect(sockfd, &netaddr,PR_INTERVAL_NO_TIMEOUT) < 0) {
+ fprintf(stderr,"prsocket_test: PR_Connect failed\n");
+ failed_already=1;
+ return;
+ }
+ /*
+ * read the small file and verify the data
+ */
+ if (readn(sockfd, small_buf, SMALL_FILE_SIZE + SMALL_FILE_HEADER_SIZE)
+ != (SMALL_FILE_SIZE + SMALL_FILE_HEADER_SIZE)) {
+ fprintf(stderr,
+ "prsocket_test: TransmitFile_Client failed to receive file\n");
+ failed_already=1;
+ return;
+ }
+#if defined(XP_UNIX)
+ /* File transmission test can not be done because of large file's size */
+ if (memcmp(small_file_header, small_buf, SMALL_FILE_HEADER_SIZE) != 0) {
+ fprintf(stderr,
+ "prsocket_test: TransmitFile_Client ERROR - small file header data corruption\n");
+ failed_already=1;
+ return;
+ }
+ if (memcmp(small_file_addr, small_buf + SMALL_FILE_HEADER_SIZE,
+ SMALL_FILE_SIZE) != 0) {
+ fprintf(stderr,
+ "prsocket_test: TransmitFile_Client ERROR - small file data corruption\n");
+ failed_already=1;
+ return;
+ }
+#endif
+ /*
+ * read the large file and verify the data
+ */
+ if (readn(sockfd, large_buf, LARGE_FILE_SIZE) != LARGE_FILE_SIZE) {
+ fprintf(stderr,
+ "prsocket_test: TransmitFile_Client failed to receive file\n");
+ failed_already=1;
+ return;
+ }
+#if defined(XP_UNIX)
+ if (memcmp(large_file_addr, large_buf, LARGE_FILE_SIZE) != 0) {
+ fprintf(stderr,
+ "prsocket_test: TransmitFile_Client ERROR - large file data corruption\n");
+ 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;
+ }
+#if defined(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;
+ }
+#if defined(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;
+ }
+#if defined(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;
+ }
+#if defined(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;
+ }
+#if defined(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;
+ }
+#if defined(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 header
+ */
+ 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;
+ }
+#if defined(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
+ /*
+ * case 8: partial large file at non-zero, page-aligned offset, with
+ * header and trailer
+ */
+ rlen = LARGE_FILE_LEN_4 + 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;
+ }
+#if defined(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((char *)large_file_addr + LARGE_FILE_OFFSET_4,
+ large_buf + LARGE_FILE_HEADER_SIZE,
+ LARGE_FILE_LEN_4) != 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_4,
+ LARGE_FILE_TRAILER_SIZE) != 0) {
+ fprintf(stderr,
+ "SendFile 2. ERROR - large file trailer 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
+ */
+
+ PR_EnterMonitor(cp->exit_mon);
+ --(*cp->exit_counter);
+ PR_Notify(cp->exit_mon);
+ PR_ExitMonitor(cp->exit_mon);
+ DPRINTF(("TransmitFile_Client [0x%lx] exiting\n", PR_GetCurrentThread()));
+}
+
+/*
+ * Serve_TransmitFile_Client
+ * Thread, started by the server, for serving a client connection.
+ * Trasmits a small file, with a header, and a large file, without
+ * a header
+ */
+static void
+Serve_TransmitFile_Client(void *arg)
+{
+ Serve_Client_Param *scp = (Serve_Client_Param *) arg;
+ PRFileDesc *sockfd;
+ 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);
+
+ if (local_small_file_fd == NULL) {
+ fprintf(stderr,"prsocket_test failed to open file for transmitting %s\n",
+ SMALL_FILE_NAME);
+ failed_already=1;
+ goto done;
+ }
+ local_large_file_fd = PR_Open(LARGE_FILE_NAME, PR_RDONLY,0);
+
+ if (local_large_file_fd == NULL) {
+ fprintf(stderr,"prsocket_test failed to open file for transmitting %s\n",
+ LARGE_FILE_NAME);
+ failed_already=1;
+ goto done;
+ }
+ bytes = PR_TransmitFile(sockfd, local_small_file_fd, small_file_header,
+ SMALL_FILE_HEADER_SIZE, PR_TRANSMITFILE_KEEP_OPEN,
+ PR_INTERVAL_NO_TIMEOUT);
+ if (bytes != (SMALL_FILE_SIZE+ SMALL_FILE_HEADER_SIZE)) {
+ fprintf(stderr,
+ "prsocet_test: PR_TransmitFile failed: (%ld, %ld)\n",
+ PR_GetError(), PR_GetOSError());
+ failed_already=1;
+ }
+ bytes = PR_TransmitFile(sockfd, local_large_file_fd, NULL, 0,
+ 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_KEEP_OPEN,
+ 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;
+ }
+ /*
+ * case 8: partial large file at non-zero page-aligned offset,
+ * with header and trailer
+ */
+ sfd.fd = local_large_file_fd;
+ sfd.file_offset = LARGE_FILE_OFFSET_4;
+ sfd.file_nbytes = LARGE_FILE_LEN_4;
+ 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_CLOSE_SOCKET,
+ PR_INTERVAL_NO_TIMEOUT);
+ slen = LARGE_FILE_LEN_4 + 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;
+ }
+done:
+ if (local_small_file_fd != NULL) {
+ PR_Close(local_small_file_fd);
+ }
+ if (local_large_file_fd != NULL) {
+ PR_Close(local_large_file_fd);
+ }
+}
+
+/*
+ * TransmitFile Server
+ * Server Thread
+ * Bind an address to a socket and listen for incoming connections
+ * Create worker threads to service clients
+ */
+static void
+TransmitFile_Server(void *arg)
+{
+ PRThread **t = NULL; /* an array of PRThread pointers */
+ Server_Param *sp = (Server_Param *) arg;
+ Serve_Client_Param *scp;
+ PRFileDesc *sockfd = NULL, *newsockfd;
+ PRNetAddr netaddr;
+ PRInt32 i;
+
+ t = (PRThread**)PR_MALLOC(num_transmitfile_clients * sizeof(PRThread *));
+ if (t == NULL) {
+ fprintf(stderr, "prsocket_test: run out of memory\n");
+ failed_already=1;
+ goto exit;
+ }
+ /*
+ * Create a tcp socket
+ */
+ if ((sockfd = PR_OpenTCPSocket(PR_AF_INET)) == NULL) {
+ fprintf(stderr,"prsocket_test: PR_OpenTCPSocket failed\n");
+ failed_already=1;
+ goto exit;
+ }
+ memset(&netaddr, 0, sizeof(netaddr));
+ netaddr.inet.family = PR_AF_INET;
+ netaddr.inet.port = PR_htons(TCP_SERVER_PORT);
+ netaddr.inet.ip = PR_htonl(PR_INADDR_ANY);
+ /*
+ * try a few times to bind server's address, if addresses are in
+ * use
+ */
+ i = 0;
+ while (PR_Bind(sockfd, &netaddr) < 0) {
+ if (PR_GetError() == PR_ADDRESS_IN_USE_ERROR) {
+ netaddr.inet.port += 2;
+ if (i++ < SERVER_MAX_BIND_COUNT) {
+ continue;
+ }
+ }
+ fprintf(stderr,"prsocket_test: ERROR - PR_Bind failed\n");
+ failed_already=1;
+ perror("PR_Bind");
+ goto exit;
+ }
+
+ if (PR_Listen(sockfd, 32) < 0) {
+ fprintf(stderr,"prsocket_test: ERROR - PR_Listen failed\n");
+ failed_already=1;
+ goto exit;
+ }
+
+ if (PR_GetSockName(sockfd, &netaddr) < 0) {
+ fprintf(stderr,
+ "prsocket_test: ERROR - PR_GetSockName failed\n");
+ failed_already=1;
+ goto exit;
+ }
+
+ DPRINTF(("TCP_Server: PR_BIND netaddr.inet.ip = 0x%lx, netaddr.inet.port = %d\n",
+ netaddr.inet.ip, netaddr.inet.port));
+ tcp_server_addr.inet.family = netaddr.inet.family;
+ tcp_server_addr.inet.port = netaddr.inet.port;
+ tcp_server_addr.inet.ip = netaddr.inet.ip;
+
+ /*
+ * Wake up parent thread because server address is bound and made
+ * available in the global variable 'tcp_server_addr'
+ */
+ PR_PostSem(sp->addr_sem);
+
+ for (i = 0; i < num_transmitfile_clients ; i++) {
+ /* test both null and non-null 'addr' argument to PR_Accept */
+ PRNetAddr *addrp = (i%2 ? &netaddr: NULL);
+
+ if ((newsockfd = PR_Accept(sockfd, addrp,
+ PR_INTERVAL_NO_TIMEOUT)) == NULL) {
+ fprintf(stderr,
+ "prsocket_test: ERROR - PR_Accept failed\n");
+ failed_already=1;
+ goto exit;
+ }
+ /* test both regular and emulated PR_SendFile */
+ if (i%2) {
+ PRFileDesc *layer = PR_CreateIOLayerStub(
+ emuSendFileIdentity, &emuSendFileMethods);
+ if (layer == NULL) {
+ fprintf(stderr,
+ "prsocket_test: ERROR - PR_CreateIOLayerStub failed\n");
+ failed_already=1;
+ goto exit;
+ }
+ if (PR_PushIOLayer(newsockfd, PR_TOP_IO_LAYER, layer)
+ == PR_FAILURE) {
+ fprintf(stderr,
+ "prsocket_test: ERROR - PR_PushIOLayer failed\n");
+ failed_already=1;
+ goto exit;
+ }
+ }
+ scp = PR_NEW(Serve_Client_Param);
+ if (scp == NULL) {
+ fprintf(stderr,"prsocket_test: PR_NEW failed\n");
+ failed_already=1;
+ goto exit;
+ }
+
+ /*
+ * Start a Serve_Client thread for each incoming connection
+ */
+ scp->sockfd = newsockfd;
+ scp->datalen = sp->datalen;
+
+ t[i] = PR_CreateThread(PR_USER_THREAD,
+ Serve_TransmitFile_Client, (void *)scp,
+ PR_PRIORITY_NORMAL,
+ PR_LOCAL_THREAD,
+ PR_JOINABLE_THREAD,
+ 0);
+ if (t[i] == NULL) {
+ fprintf(stderr,
+ "prsocket_test: PR_CreateThread failed\n");
+ failed_already=1;
+ goto exit;
+ }
+ DPRINTF(("TransmitFile_Server: Created Serve_TransmitFile_Client = 0x%lx\n", t));
+ }
+
+ /*
+ * Wait for all the worker threads to end, so that we know
+ * they are no longer using the small and large file fd's.
+ */
+
+ for (i = 0; i < num_transmitfile_clients; i++) {
+ PR_JoinThread(t[i]);
+ }
+
+exit:
+ if (t) {
+ PR_DELETE(t);
+ }
+ if (sockfd) {
+ PR_Close(sockfd);
+ }
+
+ /*
+ * Decrement exit_counter and notify parent thread
+ */
+
+ PR_EnterMonitor(sp->exit_mon);
+ --(*sp->exit_counter);
+ PR_Notify(sp->exit_mon);
+ PR_ExitMonitor(sp->exit_mon);
+ DPRINTF(("TransmitFile_Server [0x%lx] exiting\n", PR_GetCurrentThread()));
+}
+
+/*
+ * Socket_Misc_Test - test miscellaneous functions
+ *
+ */
+static PRInt32
+Socket_Misc_Test(void)
+{
+ PRIntn i, rv = 0, bytes, count, len;
+ PRThread *t;
+ PRSemaphore *server_sem;
+ Server_Param *sparamp;
+ Client_Param *cparamp;
+ PRMonitor *mon2;
+ PRInt32 datalen;
+
+ /*
+ * We deliberately pick a buffer size that is not a nice multiple
+ * of 1024.
+ */
+#define TRANSMITFILE_BUF_SIZE (4 * 1024 - 11)
+
+ typedef struct {
+ char data[TRANSMITFILE_BUF_SIZE];
+ } file_buf;
+ file_buf *buf = NULL;
+
+ /*
+ * create file(s) to be transmitted
+ */
+ if ((PR_MkDir(TEST_DIR, 0777)) < 0) {
+ printf("prsocket_test failed to create dir %s\n",TEST_DIR);
+ failed_already=1;
+ return -1;
+ }
+
+ small_file_fd = PR_Open(SMALL_FILE_NAME, PR_RDWR | PR_CREATE_FILE,0777);
+
+ if (small_file_fd == NULL) {
+ fprintf(stderr,"prsocket_test failed to create/open file %s\n",
+ SMALL_FILE_NAME);
+ failed_already=1;
+ rv = -1;
+ goto done;
+ }
+ buf = PR_NEW(file_buf);
+ if (buf == NULL) {
+ fprintf(stderr,"prsocket_test failed to allocate buffer\n");
+ failed_already=1;
+ rv = -1;
+ goto done;
+ }
+ /*
+ * fill in random data
+ */
+ for (i = 0; i < TRANSMITFILE_BUF_SIZE; i++) {
+ buf->data[i] = i;
+ }
+ count = 0;
+ do {
+ len = (SMALL_FILE_SIZE - count) > TRANSMITFILE_BUF_SIZE ?
+ TRANSMITFILE_BUF_SIZE : (SMALL_FILE_SIZE - count);
+ bytes = PR_Write(small_file_fd, buf->data, len);
+ if (bytes <= 0) {
+ fprintf(stderr,
+ "prsocket_test failed to write to file %s\n",
+ SMALL_FILE_NAME);
+ failed_already=1;
+ rv = -1;
+ goto done;
+ }
+ count += bytes;
+ } while (count < SMALL_FILE_SIZE);
+#ifdef XP_UNIX
+ /*
+ * map the small file; used in checking for data corruption
+ */
+ small_file_addr = mmap(0, SMALL_FILE_SIZE, PROT_READ,
+ 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);
+ failed_already=1;
+ rv = -1;
+ goto done;
+ }
+#endif
+ /*
+ * header for small file
+ */
+ small_file_header = PR_MALLOC(SMALL_FILE_HEADER_SIZE);
+ if (small_file_header == NULL) {
+ fprintf(stderr,"prsocket_test failed to malloc header file\n");
+ failed_already=1;
+ rv = -1;
+ goto done;
+ }
+ 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);
+
+ if (large_file_fd == NULL) {
+ fprintf(stderr,"prsocket_test failed to create/open file %s\n",
+ LARGE_FILE_NAME);
+ failed_already=1;
+ rv = -1;
+ goto done;
+ }
+ /*
+ * fill in random data
+ */
+ for (i = 0; i < TRANSMITFILE_BUF_SIZE; i++) {
+ buf->data[i] = i;
+ }
+ count = 0;
+ do {
+ len = (LARGE_FILE_SIZE - count) > TRANSMITFILE_BUF_SIZE ?
+ TRANSMITFILE_BUF_SIZE : (LARGE_FILE_SIZE - count);
+ bytes = PR_Write(large_file_fd, buf->data, len);
+ if (bytes <= 0) {
+ fprintf(stderr,
+ "prsocket_test failed to write to file %s: (%ld, %ld)\n",
+ LARGE_FILE_NAME,
+ PR_GetError(), PR_GetOSError());
+ failed_already=1;
+ rv = -1;
+ goto done;
+ }
+ count += bytes;
+ } while (count < LARGE_FILE_SIZE);
+#if defined(XP_UNIX)
+ /*
+ * map the large file; used in checking for data corruption
+ */
+ large_file_addr = mmap(0, LARGE_FILE_SIZE, PROT_READ,
+ 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);
+ failed_already=1;
+ rv = -1;
+ 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;
+ /*
+ * start the server thread
+ */
+ sparamp = PR_NEW(Server_Param);
+ if (sparamp == NULL) {
+ fprintf(stderr,"prsocket_test: PR_NEW failed\n");
+ failed_already=1;
+ rv = -1;
+ goto done;
+ }
+ server_sem = PR_NewSem(0);
+ if (server_sem == NULL) {
+ fprintf(stderr,"prsocket_test: PR_NewSem failed\n");
+ failed_already=1;
+ rv = -1;
+ goto done;
+ }
+ mon2 = PR_NewMonitor();
+ if (mon2 == NULL) {
+ fprintf(stderr,"prsocket_test: PR_NewMonitor failed\n");
+ failed_already=1;
+ rv = -1;
+ goto done;
+ }
+ PR_EnterMonitor(mon2);
+
+ sparamp->addr_sem = server_sem;
+ sparamp->exit_mon = mon2;
+ sparamp->exit_counter = &thread_count;
+ sparamp->datalen = datalen;
+ t = PR_CreateThread(PR_USER_THREAD,
+ TransmitFile_Server, (void *)sparamp,
+ PR_PRIORITY_NORMAL,
+ PR_LOCAL_THREAD,
+ PR_UNJOINABLE_THREAD,
+ 0);
+ if (t == NULL) {
+ fprintf(stderr,"prsocket_test: PR_CreateThread failed\n");
+ failed_already=1;
+ rv = -1;
+ goto done;
+ }
+ DPRINTF(("Created TCP server = 0x%x\n", t));
+ thread_count++;
+
+ /*
+ * wait till the server address is setup
+ */
+ PR_WaitSem(server_sem);
+
+ /*
+ * Now start a bunch of client threads
+ */
+
+ cparamp = PR_NEW(Client_Param);
+ if (cparamp == NULL) {
+ fprintf(stderr,"prsocket_test: PR_NEW failed\n");
+ failed_already=1;
+ rv = -1;
+ goto done;
+ }
+ cparamp->server_addr = tcp_server_addr;
+ cparamp->server_addr.inet.ip = PR_htonl(PR_INADDR_LOOPBACK);
+ cparamp->exit_mon = mon2;
+ cparamp->exit_counter = &thread_count;
+ cparamp->datalen = datalen;
+ for (i = 0; i < num_transmitfile_clients; i++) {
+ t = create_new_thread(PR_USER_THREAD,
+ TransmitFile_Client, (void *) cparamp,
+ PR_PRIORITY_NORMAL,
+ PR_LOCAL_THREAD,
+ PR_UNJOINABLE_THREAD,
+ 0, i);
+ if (t == NULL) {
+ fprintf(stderr,"prsocket_test: PR_CreateThread failed\n");
+ rv = -1;
+ failed_already=1;
+ goto done;
+ }
+ DPRINTF(("Created TransmitFile client = 0x%lx\n", t));
+ thread_count++;
+ }
+ /* Wait for server and client threads to exit */
+ while (thread_count) {
+ PR_Wait(mon2, PR_INTERVAL_NO_TIMEOUT);
+ DPRINTF(("Socket_Misc_Test - thread_count = %d\n", thread_count));
+ }
+ PR_ExitMonitor(mon2);
+done:
+ if (buf) {
+ PR_DELETE(buf);
+ }
+#if defined(XP_UNIX)
+ munmap((char*)small_file_addr, SMALL_FILE_SIZE);
+ munmap((char*)large_file_addr, LARGE_FILE_SIZE);
+#endif
+ PR_Close(small_file_fd);
+ PR_Close(large_file_fd);
+ if ((PR_Delete(SMALL_FILE_NAME)) == PR_FAILURE) {
+ fprintf(stderr,"prsocket_test: failed to unlink file %s\n",
+ SMALL_FILE_NAME);
+ failed_already=1;
+ }
+ if ((PR_Delete(LARGE_FILE_NAME)) == PR_FAILURE) {
+ fprintf(stderr,"prsocket_test: failed to unlink file %s\n",
+ LARGE_FILE_NAME);
+ failed_already=1;
+ }
+ if ((PR_RmDir(TEST_DIR)) == PR_FAILURE) {
+ fprintf(stderr,"prsocket_test failed to rmdir %s: (%ld, %ld)\n",
+ TEST_DIR, PR_GetError(), PR_GetOSError());
+ failed_already=1;
+ }
+
+ printf("%-29s%s","Socket_Misc_Test",":");
+ printf("%2d Server %2d Clients\n",1, num_transmitfile_clients);
+ printf("%30s Sizes of Transmitted Files - %4d KB, %2d MB \n",":",
+ SMALL_FILE_SIZE/1024, LARGE_FILE_SIZE/(1024 * 1024));
+
+
+ return rv;
+}
+/************************************************************************/
+
+/*
+ * Test Socket NSPR APIs
+ */
+
+int main(int argc, char **argv)
+{
+ /*
+ * -d debug mode
+ */
+
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "d");
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 'd': /* debug mode */
+ _debug_on = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
+ PR_STDIO_INIT();
+
+ PR_SetConcurrency(4);
+
+ emuSendFileIdentity = PR_GetUniqueIdentity("Emulated SendFile");
+ emuSendFileMethods = *PR_GetDefaultIOMethods();
+ emuSendFileMethods.transmitfile = emu_TransmitFile;
+ emuSendFileMethods.sendfile = emu_SendFile;
+
+ /*
+ * run client-server test with TCP, Ipv4-Ipv4
+ */
+ printf("TCP Client/Server Test - IPv4/Ipv4\n");
+ if (TCP_Socket_Client_Server_Test() < 0) {
+ printf("TCP_Socket_Client_Server_Test failed\n");
+ goto done;
+ } else {
+ printf("TCP_Socket_Client_Server_Test Passed\n");
+ }
+ /*
+ * client-server test, Ipv6-Ipv4
+ */
+ client_domain = PR_AF_INET6;
+ printf("TCP Client/Server Test - IPv6/Ipv4\n");
+ if (TCP_Socket_Client_Server_Test() < 0) {
+ printf("TCP_Socket_Client_Server_Test failed\n");
+ goto done;
+ } else {
+ printf("TCP_Socket_Client_Server_Test Passed\n");
+ }
+ /*
+ * client-server test, Ipv4-Ipv6
+ */
+ client_domain = PR_AF_INET;
+ server_domain = PR_AF_INET6;
+ printf("TCP Client/Server Test - IPv4/Ipv6\n");
+ if (TCP_Socket_Client_Server_Test() < 0) {
+ printf("TCP_Socket_Client_Server_Test failed\n");
+ goto done;
+ } else {
+ printf("TCP_Socket_Client_Server_Test Passed\n");
+ }
+ /*
+ * client-server test, Ipv6-Ipv6
+ */
+ client_domain = PR_AF_INET6;
+ server_domain = PR_AF_INET6;
+ printf("TCP Client/Server Test - IPv6/Ipv6\n");
+ if (TCP_Socket_Client_Server_Test() < 0) {
+ printf("TCP_Socket_Client_Server_Test failed\n");
+ goto done;
+ } else {
+ printf("TCP_Socket_Client_Server_Test Passed\n");
+ }
+ test_cancelio = 0;
+
+ /*
+ * Misc socket tests - including transmitfile, etc.
+ */
+
+ /* File transmission test can not be done in Symbian OS because of
+ * large file's size and the incomplete mmap() implementation. */
+#if !defined(WIN16)
+ /*
+ ** The 'transmit file' test does not run because
+ ** transmit file is not implemented in NSPR yet.
+ **
+ */
+ if (Socket_Misc_Test() < 0) {
+ printf("Socket_Misc_Test failed\n");
+ failed_already=1;
+ goto done;
+ } else {
+ printf("Socket_Misc_Test passed\n");
+ }
+
+ /*
+ * run client-server test with TCP again to test
+ * recycling used sockets from PR_TransmitFile().
+ */
+ if (TCP_Socket_Client_Server_Test() < 0) {
+ printf("TCP_Socket_Client_Server_Test failed\n");
+ goto done;
+ } else {
+ printf("TCP_Socket_Client_Server_Test Passed\n");
+ }
+#endif
+
+done:
+ PR_Cleanup();
+ if (failed_already) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+}
diff --git a/nsprpub/pr/tests/sockopt.c b/nsprpub/pr/tests/sockopt.c
new file mode 100644
index 0000000000..540a19b90b
--- /dev/null
+++ b/nsprpub/pr/tests/sockopt.c
@@ -0,0 +1,178 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nspr.h"
+#include "prio.h"
+#include "prinit.h"
+#include "prprf.h"
+#include "obsolete/probslet.h"
+
+#include "plerror.h"
+
+#ifdef XP_UNIX
+#include <sys/socket.h> /* SO_REUSEPORT */
+#endif
+
+static PRFileDesc *err = NULL;
+static PRBool failed = PR_FALSE;
+
+static void Failed(const char *msg1, const char *msg2)
+{
+ if (NULL != msg1) {
+ PR_fprintf(err, "%s ", msg1);
+ }
+ PL_FPrintError(err, msg2);
+ failed = PR_TRUE;
+} /* Failed */
+
+static PRSockOption Incr(PRSockOption *option)
+{
+ PRIntn val = ((PRIntn)*option) + 1;
+ *option = (PRSockOption)val;
+ return (PRSockOption)val;
+} /* Incr */
+
+int main(int argc, char **argv)
+{
+ PRStatus rv;
+ PRFileDesc *udp = PR_NewUDPSocket();
+ PRFileDesc *tcp = PR_NewTCPSocket();
+ const char *tag[] =
+ {
+ "PR_SockOpt_Nonblocking", /* nonblocking io */
+ "PR_SockOpt_Linger", /* linger on close if data present */
+ "PR_SockOpt_Reuseaddr", /* allow local address reuse */
+ "PR_SockOpt_Keepalive", /* keep connections alive */
+ "PR_SockOpt_RecvBufferSize", /* receive buffer size */
+ "PR_SockOpt_SendBufferSize", /* send buffer size */
+
+ "PR_SockOpt_IpTimeToLive", /* time to live */
+ "PR_SockOpt_IpTypeOfService", /* type of service and precedence */
+
+ "PR_SockOpt_AddMember", /* add an IP group membership */
+ "PR_SockOpt_DropMember", /* drop an IP group membership */
+ "PR_SockOpt_McastInterface", /* multicast interface address */
+ "PR_SockOpt_McastTimeToLive", /* multicast timetolive */
+ "PR_SockOpt_McastLoopback", /* multicast loopback */
+
+ "PR_SockOpt_NoDelay", /* don't delay send to coalesce packets */
+ "PR_SockOpt_MaxSegment", /* maximum segment size */
+ "PR_SockOpt_Broadcast", /* Enable broadcast */
+ "PR_SockOpt_Reuseport", /* allow local address & port reuse */
+ "PR_SockOpt_Last"
+ };
+
+ err = PR_GetSpecialFD(PR_StandardError);
+ PR_STDIO_INIT();
+
+ if (NULL == udp) {
+ Failed("PR_NewUDPSocket()", NULL);
+ }
+ else if (NULL == tcp) {
+ Failed("PR_NewTCPSocket()", NULL);
+ }
+ else
+ {
+ PRSockOption option;
+ PRUint32 segment = 1024;
+ PRNetAddr addr;
+
+ rv = PR_InitializeNetAddr(PR_IpAddrAny, 0, &addr);
+ if (PR_FAILURE == rv) {
+ Failed("PR_InitializeNetAddr()", NULL);
+ }
+ rv = PR_Bind(udp, &addr);
+ if (PR_FAILURE == rv) {
+ Failed("PR_Bind()", NULL);
+ }
+ for(option = PR_SockOpt_Linger; option < PR_SockOpt_Last; Incr(&option))
+ {
+ PRSocketOptionData data;
+ PRFileDesc *fd = tcp;
+ data.option = option;
+ switch (option)
+ {
+ case PR_SockOpt_Nonblocking:
+ data.value.non_blocking = PR_TRUE;
+ break;
+ case PR_SockOpt_Linger:
+ data.value.linger.polarity = PR_TRUE;
+ data.value.linger.linger = PR_SecondsToInterval(2);
+ break;
+ case PR_SockOpt_Reuseaddr:
+ data.value.reuse_addr = PR_TRUE;
+ break;
+ case PR_SockOpt_Keepalive:
+ data.value.keep_alive = PR_TRUE;
+ break;
+ case PR_SockOpt_RecvBufferSize:
+ data.value.recv_buffer_size = segment;
+ break;
+ case PR_SockOpt_SendBufferSize:
+ data.value.send_buffer_size = segment;
+ break;
+ case PR_SockOpt_IpTimeToLive:
+ data.value.ip_ttl = 64;
+ break;
+ case PR_SockOpt_IpTypeOfService:
+ data.value.tos = 0;
+ break;
+ case PR_SockOpt_McastTimeToLive:
+ fd = udp;
+ data.value.mcast_ttl = 4;
+ break;
+ case PR_SockOpt_McastLoopback:
+ fd = udp;
+ data.value.mcast_loopback = PR_TRUE;
+ break;
+ case PR_SockOpt_NoDelay:
+ data.value.no_delay = PR_TRUE;
+ break;
+#ifndef WIN32
+ case PR_SockOpt_MaxSegment:
+ data.value.max_segment = segment;
+ break;
+#endif
+ case PR_SockOpt_Broadcast:
+ fd = udp;
+ data.value.broadcast = PR_TRUE;
+ break;
+#ifdef SO_REUSEPORT
+ case PR_SockOpt_Reuseport:
+ data.value.reuse_port = PR_TRUE;
+ break;
+#endif
+ default: continue;
+ }
+
+ /*
+ * TCP_MAXSEG can only be read, not set
+ */
+ if (option != PR_SockOpt_MaxSegment) {
+#ifdef WIN32
+ if (option != PR_SockOpt_McastLoopback)
+#endif
+ {
+ rv = PR_SetSocketOption(fd, &data);
+ if (PR_FAILURE == rv) {
+ Failed("PR_SetSocketOption()", tag[option]);
+ }
+ }
+ }
+
+ rv = PR_GetSocketOption(fd, &data);
+ if (PR_FAILURE == rv) {
+ Failed("PR_GetSocketOption()", tag[option]);
+ }
+ }
+ PR_Close(udp);
+ PR_Close(tcp);
+ }
+ PR_fprintf(err, "%s\n", (failed) ? "FAILED" : "PASSED");
+ return (failed) ? 1 : 0;
+} /* main */
+
+/* sockopt.c */
+
diff --git a/nsprpub/pr/tests/sockping.c b/nsprpub/pr/tests/sockping.c
new file mode 100644
index 0000000000..327d1d8e1a
--- /dev/null
+++ b/nsprpub/pr/tests/sockping.c
@@ -0,0 +1,132 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * File: sockping.c
+ *
+ * Description:
+ * This test runs in conjunction with the sockpong test.
+ * This test creates a socket pair and passes one socket
+ * to the sockpong test. Then this test writes "ping" to
+ * to the sockpong test and the sockpong test writes "pong"
+ * back. To run this pair of tests, just invoke sockping.
+ *
+ * Tested areas: process creation, socket pairs, file
+ * descriptor inheritance.
+ */
+
+#include "prerror.h"
+#include "prio.h"
+#include "prproces.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#define NUM_ITERATIONS 10
+
+static char *child_argv[] = { "sockpong", NULL };
+
+int main(int argc, char **argv)
+{
+ PRFileDesc *sock[2];
+ PRStatus status;
+ PRProcess *process;
+ PRProcessAttr *attr;
+ char buf[1024];
+ PRInt32 nBytes;
+ PRInt32 exitCode;
+ int idx;
+
+ status = PR_NewTCPSocketPair(sock);
+ if (status == PR_FAILURE) {
+ fprintf(stderr, "PR_NewTCPSocketPair failed\n");
+ exit(1);
+ }
+
+ status = PR_SetFDInheritable(sock[0], PR_FALSE);
+ if (status == PR_FAILURE) {
+ fprintf(stderr, "PR_SetFDInheritable failed: (%d, %d)\n",
+ PR_GetError(), PR_GetOSError());
+ exit(1);
+ }
+ status = PR_SetFDInheritable(sock[1], PR_TRUE);
+ if (status == PR_FAILURE) {
+ fprintf(stderr, "PR_SetFDInheritable failed: (%d, %d)\n",
+ PR_GetError(), PR_GetOSError());
+ exit(1);
+ }
+
+ attr = PR_NewProcessAttr();
+ if (attr == NULL) {
+ fprintf(stderr, "PR_NewProcessAttr failed\n");
+ exit(1);
+ }
+
+ status = PR_ProcessAttrSetInheritableFD(attr, sock[1], "SOCKET");
+ if (status == PR_FAILURE) {
+ fprintf(stderr, "PR_ProcessAttrSetInheritableFD failed\n");
+ exit(1);
+ }
+
+ process = PR_CreateProcess(child_argv[0], child_argv, NULL, attr);
+ if (process == NULL) {
+ fprintf(stderr, "PR_CreateProcess failed\n");
+ exit(1);
+ }
+ PR_DestroyProcessAttr(attr);
+ status = PR_Close(sock[1]);
+ if (status == PR_FAILURE) {
+ fprintf(stderr, "PR_Close failed\n");
+ exit(1);
+ }
+
+ for (idx = 0; idx < NUM_ITERATIONS; idx++) {
+ strcpy(buf, "ping");
+ printf("ping process: sending \"%s\"\n", buf);
+ nBytes = PR_Write(sock[0], buf, 5);
+ if (nBytes == -1) {
+ fprintf(stderr, "PR_Write failed: (%d, %d)\n",
+ PR_GetError(), PR_GetOSError());
+ exit(1);
+ }
+ memset(buf, 0, sizeof(buf));
+ nBytes = PR_Read(sock[0], buf, sizeof(buf));
+ if (nBytes == -1) {
+ fprintf(stderr, "PR_Read failed: (%d, %d)\n",
+ PR_GetError(), PR_GetOSError());
+ exit(1);
+ }
+ printf("ping process: received \"%s\"\n", buf);
+ if (nBytes != 5) {
+ fprintf(stderr, "ping process: expected 5 bytes but got %d bytes\n",
+ nBytes);
+ exit(1);
+ }
+ if (strcmp(buf, "pong") != 0) {
+ fprintf(stderr, "ping process: expected \"pong\" but got \"%s\"\n",
+ buf);
+ exit(1);
+ }
+ }
+
+ status = PR_Close(sock[0]);
+ if (status == PR_FAILURE) {
+ fprintf(stderr, "PR_Close failed\n");
+ exit(1);
+ }
+ status = PR_WaitProcess(process, &exitCode);
+ if (status == PR_FAILURE) {
+ fprintf(stderr, "PR_WaitProcess failed\n");
+ exit(1);
+ }
+ if (exitCode == 0) {
+ printf("PASS\n");
+ return 0;
+ } else {
+ printf("FAIL\n");
+ return 1;
+ }
+}
diff --git a/nsprpub/pr/tests/sockpong.c b/nsprpub/pr/tests/sockpong.c
new file mode 100644
index 0000000000..31cfd3ee8c
--- /dev/null
+++ b/nsprpub/pr/tests/sockpong.c
@@ -0,0 +1,83 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * File: sockpong.c
+ *
+ * Description:
+ * This test runs in conjunction with the sockping test.
+ * The sockping test creates a socket pair and passes one
+ * socket to this test. Then the sockping test writes
+ * "ping" to this test and this test writes "pong" back.
+ * To run this pair of tests, just invoke sockping.
+ *
+ * Tested areas: process creation, socket pairs, file
+ * descriptor inheritance.
+ */
+
+#include "prerror.h"
+#include "prio.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#define NUM_ITERATIONS 10
+
+int main(int argc, char **argv)
+{
+ PRFileDesc *sock;
+ PRStatus status;
+ char buf[1024];
+ PRInt32 nBytes;
+ int idx;
+
+ sock = PR_GetInheritedFD("SOCKET");
+ if (sock == NULL) {
+ fprintf(stderr, "PR_GetInheritedFD failed\n");
+ exit(1);
+ }
+ status = PR_SetFDInheritable(sock, PR_FALSE);
+ if (status == PR_FAILURE) {
+ fprintf(stderr, "PR_SetFDInheritable failed\n");
+ exit(1);
+ }
+
+ for (idx = 0; idx < NUM_ITERATIONS; idx++) {
+ memset(buf, 0, sizeof(buf));
+ nBytes = PR_Read(sock, buf, sizeof(buf));
+ if (nBytes == -1) {
+ fprintf(stderr, "PR_Read failed: (%d, %d)\n",
+ PR_GetError(), PR_GetOSError());
+ exit(1);
+ }
+ printf("pong process: received \"%s\"\n", buf);
+ if (nBytes != 5) {
+ fprintf(stderr, "pong process: expected 5 bytes but got %d bytes\n",
+ nBytes);
+ exit(1);
+ }
+ if (strcmp(buf, "ping") != 0) {
+ fprintf(stderr, "pong process: expected \"ping\" but got \"%s\"\n",
+ buf);
+ exit(1);
+ }
+
+ strcpy(buf, "pong");
+ printf("pong process: sending \"%s\"\n", buf);
+ nBytes = PR_Write(sock, buf, 5);
+ if (nBytes == -1) {
+ fprintf(stderr, "PR_Write failed\n");
+ exit(1);
+ }
+ }
+
+ status = PR_Close(sock);
+ if (status == PR_FAILURE) {
+ fprintf(stderr, "PR_Close failed\n");
+ exit(1);
+ }
+ return 0;
+}
diff --git a/nsprpub/pr/tests/sprintf.c b/nsprpub/pr/tests/sprintf.c
new file mode 100644
index 0000000000..51db026d1c
--- /dev/null
+++ b/nsprpub/pr/tests/sprintf.c
@@ -0,0 +1,459 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * File: sprintf.c
+ * Description:
+ * This is a test program for the PR_snprintf() functions defined
+ * in prprf.c. This test program is based on ns/nspr/tests/sprintf.c,
+ * revision 1.10.
+ * Modification History:
+ * 20-May-1997 AGarcia replaced printf statment to return PASS\n. This is to be used by the
+ * regress tool parsing routine.
+ ** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to
+ * recognize the return code from tha main program.
+ */
+
+#include "prinit.h"
+#include "prprf.h"
+#include "prlog.h"
+#include "prlong.h"
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+static char sbuf[20000];
+
+
+/*
+** Perform a three way test against PR_smprintf, PR_snprintf, and sprintf.
+** Make sure the results are identical
+*/
+static void test_i(char *pattern, int i)
+{
+ char *s;
+ char buf[200];
+ int n;
+
+ /* try all three routines */
+ s = PR_smprintf(pattern, i);
+ PR_ASSERT(s != 0);
+ n = PR_snprintf(buf, sizeof(buf), pattern, i);
+ PR_ASSERT(n <= sizeof(buf));
+ sprintf(sbuf, pattern, i);
+
+ /* compare results */
+ if ((strncmp(s, buf, sizeof(buf)) != 0) ||
+ (strncmp(s, sbuf, sizeof(sbuf)) != 0)) {
+ fprintf(stderr,
+ "pattern='%s' i=%d\nPR_smprintf='%s'\nPR_snprintf='%s'\n sprintf='%s'\n",
+ pattern, i, s, buf, sbuf);
+ PR_smprintf_free(s);
+ exit(-1);
+ }
+ PR_smprintf_free(s);
+}
+
+static void TestI(void)
+{
+ static int nums[] = {
+ 0, 1, -1, 10, -10,
+ 32767, -32768,
+ };
+ static char *signs[] = {
+ "",
+ "0", "-", "+", " ",
+ "0-", "0+", "0 ", "-0", "-+", "- ",
+ "+0", "+-", "+ ", " 0", " -", " +",
+ "0-+", "0- ", "0+-", "0+ ", "0 -", "0 +",
+ "-0+", "-0 ", "-+0", "-+ ", "- 0", "- +",
+ "+0-", "+0 ", "+-0", "+- ", "+ 0", "+ -",
+ " 0-", " 0+", " -0", " -+", " +0", " +-",
+ "0-+ ", "0- +", "0+- ", "0+ -", "0 -+", "0 +-",
+ "-0+ ", "-0 +", "-+0 ", "-+ 0", "- 0+", "- +0",
+ "+0- ", "+0 -", "+-0 ", "+- 0", "+ 0-", "+ -0",
+ " 0-+", " 0+-", " -0+", " -+0", " +0-", " +-0",
+ };
+ static char *precs[] = {
+ "", "3", "5", "43",
+ "7.3", "7.5", "7.11", "7.43",
+ };
+ static char *formats[] = {
+ "d", "o", "x", "u",
+ "hd", "ho", "hx", "hu"
+ };
+ int f, s, n, p;
+ char fmt[20];
+
+ for (f = 0; f < PR_ARRAY_SIZE(formats); f++) {
+ for (s = 0; s < PR_ARRAY_SIZE(signs); s++) {
+ for (p = 0; p < PR_ARRAY_SIZE(precs); p++) {
+ fmt[0] = '%';
+ fmt[1] = 0;
+ if (signs[s]) {
+ strcat(fmt, signs[s]);
+ }
+ if (precs[p]) {
+ strcat(fmt, precs[p]);
+ }
+ if (formats[f]) {
+ strcat(fmt, formats[f]);
+ }
+ for (n = 0; n < PR_ARRAY_SIZE(nums); n++) {
+ test_i(fmt, nums[n]);
+ }
+ }
+ }
+ }
+}
+
+/************************************************************************/
+
+/*
+** Perform a three way test against PR_smprintf, PR_snprintf, and sprintf.
+** Make sure the results are identical
+*/
+static void test_l(char *pattern, char *spattern, PRInt32 l)
+{
+ char *s;
+ char buf[200];
+ int n;
+
+ /* try all three routines */
+ s = PR_smprintf(pattern, l);
+ PR_ASSERT(s != 0);
+ n = PR_snprintf(buf, sizeof(buf), pattern, l);
+ PR_ASSERT(n <= sizeof(buf));
+ sprintf(sbuf, spattern, l);
+
+ /* compare results */
+ if ((strncmp(s, buf, sizeof(buf)) != 0) ||
+ (strncmp(s, sbuf, sizeof(sbuf)) != 0)) {
+ fprintf(stderr,
+ "pattern='%s' l=%ld\nPR_smprintf='%s'\nPR_snprintf='%s'\n sprintf='%s'\n",
+ pattern, l, s, buf, sbuf);
+ PR_smprintf_free(s);
+ exit(-1);
+ }
+ PR_smprintf_free(s);
+}
+
+static void TestL(void)
+{
+ static PRInt32 nums[] = {
+ 0,
+ 1,
+ -1,
+ 10,
+ -10,
+ 32767,
+ -32768,
+ PR_INT32(0x7fffffff), /* 2147483647L */
+ -1 - PR_INT32(0x7fffffff) /* -2147483648L */
+ };
+ static char *signs[] = {
+ "",
+ "0", "-", "+", " ",
+ "0-", "0+", "0 ", "-0", "-+", "- ",
+ "+0", "+-", "+ ", " 0", " -", " +",
+ "0-+", "0- ", "0+-", "0+ ", "0 -", "0 +",
+ "-0+", "-0 ", "-+0", "-+ ", "- 0", "- +",
+ "+0-", "+0 ", "+-0", "+- ", "+ 0", "+ -",
+ " 0-", " 0+", " -0", " -+", " +0", " +-",
+ "0-+ ", "0- +", "0+- ", "0+ -", "0 -+", "0 +-",
+ "-0+ ", "-0 +", "-+0 ", "-+ 0", "- 0+", "- +0",
+ "+0- ", "+0 -", "+-0 ", "+- 0", "+ 0-", "+ -0",
+ " 0-+", " 0+-", " -0+", " -+0", " +0-", " +-0",
+ };
+ static char *precs[] = {
+ "", "3", "5", "43",
+ ".3", ".43",
+ "7.3", "7.5", "7.11", "7.43",
+ };
+ static char *formats[] = { "ld", "lo", "lx", "lu" };
+
+#if PR_BYTES_PER_INT == 4
+ static char *sformats[] = { "d", "o", "x", "u" };
+#elif PR_BYTES_PER_LONG == 4
+ static char *sformats[] = { "ld", "lo", "lx", "lu" };
+#else
+#error Neither int nor long is 4 bytes on this platform
+#endif
+
+ int f, s, n, p;
+ char fmt[40], sfmt[40];
+
+ for (f = 0; f < PR_ARRAY_SIZE(formats); f++) {
+ for (s = 0; s < PR_ARRAY_SIZE(signs); s++) {
+ for (p = 0; p < PR_ARRAY_SIZE(precs); p++) {
+ fmt[0] = '%';
+ fmt[1] = 0;
+ if (signs[s]) {
+ strcat(fmt, signs[s]);
+ }
+ if (precs[p]) {
+ strcat(fmt, precs[p]);
+ }
+ strcpy(sfmt, fmt);
+ if (formats[f]) {
+ strcat(fmt, formats[f]);
+ }
+ if (sformats[f]) {
+ strcat(sfmt, sformats[f]);
+ }
+ for (n = 0; n < PR_ARRAY_SIZE(nums); n++) {
+ test_l(fmt, sfmt, nums[n]);
+ }
+ }
+ }
+ }
+}
+
+/************************************************************************/
+
+/*
+** Perform a three way test against PR_smprintf, PR_snprintf, and sprintf.
+** Make sure the results are identical
+*/
+static void test_ll(char *pattern, char *spattern, PRInt64 l)
+{
+ char *s;
+ char buf[200];
+ int n;
+
+ /* try all three routines */
+ s = PR_smprintf(pattern, l);
+ PR_ASSERT(s != 0);
+ n = PR_snprintf(buf, sizeof(buf), pattern, l);
+ PR_ASSERT(n <= sizeof(buf));
+#if defined(HAVE_LONG_LONG)
+ sprintf(sbuf, spattern, l);
+
+ /* compare results */
+ if ((strncmp(s, buf, sizeof(buf)) != 0) ||
+ (strncmp(s, sbuf, sizeof(sbuf)) != 0)) {
+#if PR_BYTES_PER_LONG == 8
+#define FORMAT_SPEC "%ld"
+#elif defined(WIN16)
+#define FORMAT_SPEC "%Ld"
+#elif defined(WIN32)
+#define FORMAT_SPEC "%I64d"
+#else
+#define FORMAT_SPEC "%lld"
+#endif
+ fprintf(stderr,
+ "pattern='%s' ll=" FORMAT_SPEC "\nPR_smprintf='%s'\nPR_snprintf='%s'\n sprintf='%s'\n",
+ pattern, l, s, buf, sbuf);
+ printf("FAIL\n");
+ PR_smprintf_free(s);
+ exit(-1);
+ }
+ PR_smprintf_free(s);
+#else
+ /* compare results */
+ if ((strncmp(s, buf, sizeof(buf)) != 0)) {
+ fprintf(stderr,
+ "pattern='%s'\nPR_smprintf='%s'\nPR_snprintf='%s'\n sprintf='%s'\n",
+ pattern, s, buf, sbuf);
+ printf("FAIL\n");
+ PR_smprintf_free(s);
+ exit(-1);
+ }
+ PR_smprintf_free(s);
+#endif
+}
+
+static void TestLL(void)
+{
+ static PRInt64 nums[] = {
+ LL_INIT(0, 0),
+ LL_INIT(0, 1),
+ LL_INIT(0xffffffff, 0xffffffff), /* -1 */
+ LL_INIT(0, 10),
+ LL_INIT(0xffffffff, 0xfffffff6), /* -10 */
+ LL_INIT(0, 32767),
+ LL_INIT(0xffffffff, 0xffff8000), /* -32768 */
+ LL_INIT(0, 0x7fffffff), /* 2147483647 */
+ LL_INIT(0xffffffff, 0x80000000), /* -2147483648 */
+ LL_INIT(0x7fffffff, 0xffffffff), /* 9223372036854775807 */
+ LL_INIT(0x80000000, 0), /* -9223372036854775808 */
+ PR_INT64(0),
+ PR_INT64(1),
+ PR_INT64(-1),
+ PR_INT64(10),
+ PR_INT64(-10),
+ PR_INT64(32767),
+ PR_INT64(-32768),
+ PR_INT64(2147483647),
+ PR_INT64(-2147483648),
+ PR_INT64(9223372036854775807),
+ PR_INT64(-9223372036854775808)
+ };
+
+ static char *signs[] = {
+ "",
+ "0", "-", "+", " ",
+ "0-", "0+", "0 ", "-0", "-+", "- ",
+ "+0", "+-", "+ ", " 0", " -", " +",
+ "0-+", "0- ", "0+-", "0+ ", "0 -", "0 +",
+ "-0+", "-0 ", "-+0", "-+ ", "- 0", "- +",
+ "+0-", "+0 ", "+-0", "+- ", "+ 0", "+ -",
+ " 0-", " 0+", " -0", " -+", " +0", " +-",
+ "0-+ ", "0- +", "0+- ", "0+ -", "0 -+", "0 +-",
+ "-0+ ", "-0 +", "-+0 ", "-+ 0", "- 0+", "- +0",
+ "+0- ", "+0 -", "+-0 ", "+- 0", "+ 0-", "+ -0",
+ " 0-+", " 0+-", " -0+", " -+0", " +0-", " +-0",
+ };
+ static char *precs[] = {
+ "", "3", "5", "43",
+ ".3", ".43",
+ "7.3", "7.5", "7.11", "7.43",
+ };
+ static char *formats[] = { "lld", "llo", "llx", "llu" };
+
+#if PR_BYTES_PER_LONG == 8
+ static char *sformats[] = { "ld", "lo", "lx", "lu" };
+#elif defined(WIN16)
+ /* Watcom uses the format string "%Ld" instead of "%lld". */
+ static char *sformats[] = { "Ld", "Lo", "Lx", "Lu" };
+#elif defined(WIN32)
+ static char *sformats[] = { "I64d", "I64o", "I64x", "I64u" };
+#else
+ static char *sformats[] = { "lld", "llo", "llx", "llu" };
+#endif
+
+ int f, s, n, p;
+ char fmt[40], sfmt[40];
+
+ for (f = 0; f < PR_ARRAY_SIZE(formats); f++) {
+ for (s = 0; s < PR_ARRAY_SIZE(signs); s++) {
+ for (p = 0; p < PR_ARRAY_SIZE(precs); p++) {
+ fmt[0] = '%';
+ fmt[1] = 0;
+ if (signs[s]) {
+ strcat(fmt, signs[s]);
+ }
+ if (precs[p]) {
+ strcat(fmt, precs[p]);
+ }
+ strcpy(sfmt, fmt);
+ if (formats[f]) {
+ strcat(fmt, formats[f]);
+ }
+ if (sformats[f]) {
+ strcat(sfmt, sformats[f]);
+ }
+ for (n = 0; n < PR_ARRAY_SIZE(nums); n++) {
+ test_ll(fmt, sfmt, nums[n]);
+ }
+ }
+ }
+ }
+}
+
+/************************************************************************/
+
+/*
+** Perform a three way test against PR_smprintf, PR_snprintf, and sprintf.
+** Make sure the results are identical
+*/
+static void test_s(char *pattern, char *ss)
+{
+ char *s;
+ unsigned char before[8];
+ char buf[200];
+ unsigned char after[8];
+ int n;
+
+ memset(before, 0xBB, 8);
+ memset(after, 0xAA, 8);
+
+ /* try all three routines */
+ s = PR_smprintf(pattern, ss);
+ PR_ASSERT(s != 0);
+ n = PR_snprintf(buf, sizeof(buf), pattern, ss);
+ PR_ASSERT(n <= sizeof(buf));
+ sprintf(sbuf, pattern, ss);
+
+ for (n = 0; n < 8; n++) {
+ PR_ASSERT(before[n] == 0xBB);
+ PR_ASSERT(after[n] == 0xAA);
+ }
+
+ /* compare results */
+ if ((strncmp(s, buf, sizeof(buf)) != 0) ||
+ (strncmp(s, sbuf, sizeof(sbuf)) != 0)) {
+ fprintf(stderr,
+ "pattern='%s' ss=%.20s\nPR_smprintf='%s'\nPR_snprintf='%s'\n sprintf='%s'\n",
+ pattern, ss, s, buf, sbuf);
+ printf("FAIL\n");
+ PR_smprintf_free(s);
+ exit(-1);
+ }
+ PR_smprintf_free(s);
+}
+
+static void TestS(void)
+{
+ static char *strs[] = {
+ "",
+ "a",
+ "abc",
+ "abcde",
+ "abcdefABCDEF",
+ "abcdefghijklmnopqrstuvwxyz0123456789!@#$"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$"
+ "abcdefghijklmnopqrstuvwxyz0123456789!@#$",
+ };
+ /* '0' is not relevant to printing strings */
+ static char *signs[] = {
+ "",
+ "-", "+", " ",
+ "-+", "- ", "+-", "+ ", " -", " +",
+ "-+ ", "- +", "+- ", "+ -", " -+", " +-",
+ };
+ static char *precs[] = {
+ "", "3", "5", "43",
+ ".3", ".43",
+ "7.3", "7.5", "7.11", "7.43",
+ };
+ static char *formats[] = { "s" };
+ int f, s, n, p;
+ char fmt[40];
+
+ for (f = 0; f < PR_ARRAY_SIZE(formats); f++) {
+ for (s = 0; s < PR_ARRAY_SIZE(signs); s++) {
+ for (p = 0; p < PR_ARRAY_SIZE(precs); p++) {
+ fmt[0] = '%';
+ fmt[1] = 0;
+ if (signs[s]) {
+ strcat(fmt+strlen(fmt), signs[s]);
+ }
+ if (precs[p]) {
+ strcat(fmt+strlen(fmt), precs[p]);
+ }
+ if (formats[f]) {
+ strcat(fmt+strlen(fmt), formats[f]);
+ }
+ for (n = 0; n < PR_ARRAY_SIZE(strs); n++) {
+ test_s(fmt, strs[n]);
+ }
+ }
+ }
+ }
+}
+
+/************************************************************************/
+
+int main(int argc, char **argv)
+{
+ PR_STDIO_INIT();
+ TestI();
+ TestL();
+ TestLL();
+ TestS();
+ printf("PASS\n");
+ return 0;
+}
diff --git a/nsprpub/pr/tests/stack.c b/nsprpub/pr/tests/stack.c
new file mode 100644
index 0000000000..5526a27445
--- /dev/null
+++ b/nsprpub/pr/tests/stack.c
@@ -0,0 +1,282 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+
+/*
+ *
+ * Test atomic stack operations
+ *
+ * Two stacks are created and threads add data items (each containing
+ * one of the first n integers) to the first stack, remove data items
+ * from the first stack and add them to the second stack. The primordial
+ * thread compares the sum of the first n integers to the sum of the
+ * integers in the data items in the second stack. The test succeeds if
+ * they are equal.
+ */
+
+#include "nspr.h"
+#include "plgetopt.h"
+
+typedef struct _DataRecord {
+ PRInt32 data;
+ PRStackElem link;
+} DataRecord;
+
+#define RECORD_LINK_PTR(lp) ((DataRecord*) ((char*) (lp) - offsetof(DataRecord,link)))
+
+#define MAX_THREAD_CNT 100
+#define DEFAULT_THREAD_CNT 4
+#define DEFAULT_DATA_CNT 100
+#define DEFAULT_LOOP_CNT 10000
+
+/*
+ * sum of the first n numbers using the formula n*(n+1)/2
+ */
+#define SUM_OF_NUMBERS(n) ((n & 1) ? (((n + 1)/2) * n) : ((n/2) * (n+1)))
+
+typedef struct stack_data {
+ PRStack *list1;
+ PRStack *list2;
+ PRInt32 initial_data_value;
+ PRInt32 data_cnt;
+ PRInt32 loops;
+} stack_data;
+
+static void stackop(void *arg);
+
+static int _debug_on;
+
+PRFileDesc *output;
+PRFileDesc *errhandle;
+
+int main(int argc, char **argv)
+{
+ PRInt32 rv, cnt, sum;
+ DataRecord *Item;
+ PRStack *list1, *list2;
+ PRStackElem *node;
+ PRStatus rc;
+
+ PRInt32 thread_cnt = DEFAULT_THREAD_CNT;
+ PRInt32 data_cnt = DEFAULT_DATA_CNT;
+ PRInt32 loops = DEFAULT_LOOP_CNT;
+ PRThread **threads;
+ stack_data *thread_args;
+
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "dt:c:l:");
+
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 'd': /* debug mode */
+ _debug_on = 1;
+ break;
+ case 't': /* thread count */
+ thread_cnt = atoi(opt->value);
+ break;
+ case 'c': /* data count */
+ data_cnt = atoi(opt->value);
+ break;
+ case 'l': /* loop count */
+ loops = atoi(opt->value);
+ break;
+ default:
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ PR_SetConcurrency(4);
+
+ output = PR_GetSpecialFD(PR_StandardOutput);
+ errhandle = PR_GetSpecialFD(PR_StandardError);
+ list1 = PR_CreateStack("Stack_1");
+ if (list1 == NULL) {
+ PR_fprintf(errhandle, "PR_CreateStack failed - error %d\n",
+ PR_GetError());
+ return 1;
+ }
+
+ list2 = PR_CreateStack("Stack_2");
+ if (list2 == NULL) {
+ PR_fprintf(errhandle, "PR_CreateStack failed - error %d\n",
+ PR_GetError());
+ return 1;
+ }
+
+
+ threads = (PRThread**) PR_CALLOC(sizeof(PRThread*) * thread_cnt);
+ thread_args = (stack_data *) PR_CALLOC(sizeof(stack_data) * thread_cnt);
+
+ if (_debug_on)
+ PR_fprintf(output,"%s: thread_cnt = %d data_cnt = %d\n", argv[0],
+ thread_cnt, data_cnt);
+ for(cnt = 0; cnt < thread_cnt; cnt++) {
+ PRThreadScope scope;
+
+ thread_args[cnt].list1 = list1;
+ thread_args[cnt].list2 = list2;
+ thread_args[cnt].loops = loops;
+ thread_args[cnt].data_cnt = data_cnt;
+ thread_args[cnt].initial_data_value = 1 + cnt * data_cnt;
+
+ if (cnt & 1) {
+ scope = PR_GLOBAL_THREAD;
+ }
+ else {
+ scope = PR_LOCAL_THREAD;
+ }
+
+
+ threads[cnt] = PR_CreateThread(PR_USER_THREAD,
+ stackop, &thread_args[cnt],
+ PR_PRIORITY_NORMAL,
+ scope,
+ PR_JOINABLE_THREAD,
+ 0);
+ if (threads[cnt] == NULL) {
+ PR_fprintf(errhandle, "PR_CreateThread failed - error %d\n",
+ PR_GetError());
+ PR_ProcessExit(2);
+ }
+ if (_debug_on)
+ PR_fprintf(output,"%s: created thread = 0x%x\n", argv[0],
+ threads[cnt]);
+ }
+
+ for(cnt = 0; cnt < thread_cnt; cnt++) {
+ rc = PR_JoinThread(threads[cnt]);
+ PR_ASSERT(rc == PR_SUCCESS);
+ }
+
+ node = PR_StackPop(list1);
+ /*
+ * list1 should be empty
+ */
+ if (node != NULL) {
+ PR_fprintf(errhandle, "Error - Stack 1 not empty\n");
+ PR_ASSERT(node == NULL);
+ PR_ProcessExit(4);
+ }
+
+ cnt = data_cnt * thread_cnt;
+ sum = 0;
+ while (cnt-- > 0) {
+ node = PR_StackPop(list2);
+ /*
+ * There should be at least 'cnt' number of records
+ */
+ if (node == NULL) {
+ PR_fprintf(errhandle, "Error - PR_StackPop returned NULL\n");
+ PR_ProcessExit(3);
+ }
+ Item = RECORD_LINK_PTR(node);
+ sum += Item->data;
+ }
+ node = PR_StackPop(list2);
+ /*
+ * there should be exactly 'cnt' number of records
+ */
+ if (node != NULL) {
+ PR_fprintf(errhandle, "Error - Stack 2 not empty\n");
+ PR_ASSERT(node == NULL);
+ PR_ProcessExit(4);
+ }
+ PR_DELETE(threads);
+ PR_DELETE(thread_args);
+
+ PR_DestroyStack(list1);
+ PR_DestroyStack(list2);
+
+ if (sum == SUM_OF_NUMBERS(data_cnt * thread_cnt)) {
+ PR_fprintf(output, "%s successful\n", argv[0]);
+ PR_fprintf(output, "\t\tsum = 0x%x, expected = 0x%x\n", sum,
+ SUM_OF_NUMBERS(thread_cnt * data_cnt));
+ return 0;
+ } else {
+ PR_fprintf(output, "%s failed: sum = 0x%x, expected = 0x%x\n",
+ argv[0], sum,
+ SUM_OF_NUMBERS(data_cnt * thread_cnt));
+ return 2;
+ }
+}
+
+static void stackop(void *thread_arg)
+{
+ PRInt32 val, cnt, index, loops;
+ DataRecord *Items, *Item;
+ PRStack *list1, *list2;
+ PRStackElem *node;
+ stack_data *arg = (stack_data *) thread_arg;
+
+ val = arg->initial_data_value;
+ cnt = arg->data_cnt;
+ loops = arg->loops;
+ list1 = arg->list1;
+ list2 = arg->list2;
+
+ /*
+ * allocate memory for the data records
+ */
+ Items = (DataRecord *) PR_CALLOC(sizeof(DataRecord) * cnt);
+ PR_ASSERT(Items != NULL);
+ index = 0;
+
+ if (_debug_on)
+ PR_fprintf(output,
+ "Thread[0x%x] init_val = %d cnt = %d data1 = 0x%x datan = 0x%x\n",
+ PR_GetCurrentThread(), val, cnt, &Items[0], &Items[cnt-1]);
+
+
+ /*
+ * add the data records to list1
+ */
+ while (cnt-- > 0) {
+ Items[index].data = val++;
+ PR_StackPush(list1, &Items[index].link);
+ index++;
+ }
+
+ /*
+ * pop data records from list1 and add them back to list1
+ * generates contention for the stack accesses
+ */
+ while (loops-- > 0) {
+ cnt = arg->data_cnt;
+ while (cnt-- > 0) {
+ node = PR_StackPop(list1);
+ if (node == NULL) {
+ PR_fprintf(errhandle, "Error - PR_StackPop returned NULL\n");
+ PR_ASSERT(node != NULL);
+ PR_ProcessExit(3);
+ }
+ PR_StackPush(list1, node);
+ }
+ }
+ /*
+ * remove the data records from list1 and add them to list2
+ */
+ cnt = arg->data_cnt;
+ while (cnt-- > 0) {
+ node = PR_StackPop(list1);
+ if (node == NULL) {
+ PR_fprintf(errhandle, "Error - PR_StackPop returned NULL\n");
+ PR_ASSERT(node != NULL);
+ PR_ProcessExit(3);
+ }
+ PR_StackPush(list2, node);
+ }
+ if (_debug_on)
+ PR_fprintf(output,
+ "Thread[0x%x] init_val = %d cnt = %d exiting\n",
+ PR_GetCurrentThread(), val, cnt);
+
+}
+
diff --git a/nsprpub/pr/tests/stat.c b/nsprpub/pr/tests/stat.c
new file mode 100644
index 0000000000..1f870a0d42
--- /dev/null
+++ b/nsprpub/pr/tests/stat.c
@@ -0,0 +1,87 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * Program to test different ways to get file info; right now it
+ * only works for solaris and OS/2.
+ *
+ */
+#include "nspr.h"
+#include "prpriv.h"
+#include "prinrval.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef XP_OS2
+#include <io.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#endif
+
+#define DEFAULT_COUNT 100000
+PRInt32 count;
+
+#ifndef XP_PC
+char *filename = "/etc/passwd";
+#else
+char *filename = "..\\stat.c";
+#endif
+
+static void statPRStat(void)
+{
+ PRFileInfo finfo;
+ PRInt32 index = count;
+
+ for (; index--;) {
+ PR_GetFileInfo(filename, &finfo);
+ }
+}
+
+static void statStat(void)
+{
+ struct stat finfo;
+ PRInt32 index = count;
+
+ for (; index--;) {
+ stat(filename, &finfo);
+ }
+}
+
+/************************************************************************/
+
+static void Measure(void (*func)(void), const char *msg)
+{
+ PRIntervalTime start, stop;
+ double d;
+ PRInt32 tot;
+
+ start = PR_IntervalNow();
+ (*func)();
+ stop = PR_IntervalNow();
+
+ d = (double)PR_IntervalToMicroseconds(stop - start);
+ tot = PR_IntervalToMilliseconds(stop-start);
+
+ printf("%40s: %6.2f usec avg, %d msec total\n", msg, d / count, tot);
+}
+
+int main(int argc, char **argv)
+{
+ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
+ PR_STDIO_INIT();
+
+ if (argc > 1) {
+ count = atoi(argv[1]);
+ } else {
+ count = DEFAULT_COUNT;
+ }
+
+ Measure(statPRStat, "time to call PR_GetFileInfo()");
+ Measure(statStat, "time to call stat()");
+
+ PR_Cleanup();
+}
diff --git a/nsprpub/pr/tests/stdio.c b/nsprpub/pr/tests/stdio.c
new file mode 100644
index 0000000000..d8a12389b2
--- /dev/null
+++ b/nsprpub/pr/tests/stdio.c
@@ -0,0 +1,51 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * File: stdio.c
+ * Description: testing the "special" fds
+ * Modification History:
+ * 20-May-1997 AGarcia - Replace Test succeeded status with PASS. This is used by the
+ * regress tool parsing code.
+ ** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to
+** recognize the return code from tha main program.
+ */
+
+
+#include "prlog.h"
+#include "prinit.h"
+#include "prio.h"
+
+#include <stdio.h>
+#include <string.h>
+
+static PRIntn PR_CALLBACK stdio(PRIntn argc, char **argv)
+{
+ PRInt32 rv;
+
+ PRFileDesc *out = PR_GetSpecialFD(PR_StandardOutput);
+ PRFileDesc *err = PR_GetSpecialFD(PR_StandardError);
+
+ rv = PR_Write(
+ out, "This to standard out\n",
+ strlen("This to standard out\n"));
+ PR_ASSERT((PRInt32)strlen("This to standard out\n") == rv);
+ rv = PR_Write(
+ err, "This to standard err\n",
+ strlen("This to standard err\n"));
+ PR_ASSERT((PRInt32)strlen("This to standard err\n") == rv);
+
+ return 0;
+
+} /* stdio */
+
+int main(int argc, char **argv)
+{
+ PR_STDIO_INIT();
+ return PR_Initialize(stdio, argc, argv, 0);
+} /* main */
+
+
+/* stdio.c */
diff --git a/nsprpub/pr/tests/str2addr.c b/nsprpub/pr/tests/str2addr.c
new file mode 100644
index 0000000000..ad80137d4d
--- /dev/null
+++ b/nsprpub/pr/tests/str2addr.c
@@ -0,0 +1,50 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * File: str2addr.c
+ * Description: a test for PR_StringToNetAddr
+ */
+
+#include "nspr.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+/* Address string to convert */
+#define DEFAULT_IPV4_ADDR_STR "207.200.73.41"
+
+/* Expected conversion result, in network byte order */
+static unsigned char default_ipv4_addr[] = {207, 200, 73, 41};
+
+int main(int argc, char **argv)
+{
+ PRNetAddr addr;
+ const char *addrStr;
+ unsigned char *bytes;
+ int idx;
+
+ addrStr = DEFAULT_IPV4_ADDR_STR;
+ if (PR_StringToNetAddr(addrStr, &addr) == PR_FAILURE) {
+ fprintf(stderr, "PR_StringToNetAddr failed\n");
+ exit(1);
+ }
+ if (addr.inet.family != PR_AF_INET) {
+ fprintf(stderr, "addr.inet.family should be %d but is %d\n",
+ PR_AF_INET, addr.inet.family);
+ exit(1);
+ }
+ bytes = (unsigned char *) &addr.inet.ip;
+ for (idx = 0; idx < 4; idx++) {
+ if (bytes[idx] != default_ipv4_addr[idx]) {
+ fprintf(stderr, "byte %d of IPv4 addr should be %d but is %d\n",
+ idx, default_ipv4_addr[idx], bytes[idx]);
+ exit(1);
+ }
+ }
+
+ printf("PASS\n");
+ return 0;
+}
diff --git a/nsprpub/pr/tests/strod.c b/nsprpub/pr/tests/strod.c
new file mode 100644
index 0000000000..014192fa6b
--- /dev/null
+++ b/nsprpub/pr/tests/strod.c
@@ -0,0 +1,76 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "prinit.h"
+#include "prio.h"
+#include "prprf.h"
+#include "prdtoa.h"
+#include "plgetopt.h"
+
+#include <stdlib.h>
+
+static void Help(void)
+{
+ PRFileDesc *err = PR_GetSpecialFD(PR_StandardError);
+ PR_fprintf(err, "Usage: /.strod [-n n] [-l n] [-h]\n");
+ PR_fprintf(err, "\t-n n Number to translate (default: 1234567890123456789)\n");
+ PR_fprintf(err, "\t-l n Times to loop the test (default: 1)\n");
+ PR_fprintf(err, "\t-h This message and nothing else\n");
+} /* Help */
+
+static PRIntn PR_CALLBACK RealMain(PRIntn argc, char **argv)
+{
+ PLOptStatus os;
+ PRIntn loops = 1;
+ PRFloat64 answer;
+ const char *number = "1234567890123456789";
+ PRFileDesc *err = PR_GetSpecialFD(PR_StandardError);
+ PLOptState *opt = PL_CreateOptState(argc, argv, "hc:l:");
+
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 'n': /* number to translate */
+ number = opt->value;
+ break;
+ case 'l': /* number of times to run the tests */
+ loops = atoi(opt->value);
+ break;
+ case 'h': /* user wants some guidance */
+ Help(); /* so give him an earful */
+ return 2; /* but not a lot else */
+ break;
+ default:
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ PR_fprintf(err, "Settings\n");
+ PR_fprintf(err, "\tNumber to translate %s\n", number);
+ PR_fprintf(err, "\tLoops to run test: %d\n", loops);
+
+ while (loops--)
+ {
+ answer = PR_strtod(number, NULL);
+ PR_fprintf(err, "Translation = %20.0f\n", answer);
+ }
+ return 0;
+}
+
+
+
+int main(int argc, char **argv)
+{
+ PRIntn rv;
+
+ PR_STDIO_INIT();
+ rv = PR_Initialize(RealMain, argc, argv, 0);
+ return rv;
+} /* main */
diff --git a/nsprpub/pr/tests/suspend.c b/nsprpub/pr/tests/suspend.c
new file mode 100644
index 0000000000..1976b9d8c0
--- /dev/null
+++ b/nsprpub/pr/tests/suspend.c
@@ -0,0 +1,177 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nspr.h"
+#include "prpriv.h"
+#include "prinrval.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+PRMonitor *mon;
+PRInt32 count;
+PRInt32 alive;
+
+#define SLEEP_TIME 4 /* secs */
+
+void PR_CALLBACK
+Level_2_Thread(void *arg)
+{
+ PR_Sleep(PR_MillisecondsToInterval(4 * 1000));
+ printf("Level_2_Thread[0x%lx] exiting\n",PR_GetCurrentThread());
+ return;
+}
+
+void PR_CALLBACK
+Level_1_Thread(void *arg)
+{
+ PRUint32 tmp = (PRUint32)arg;
+ PRThreadScope scope = (PRThreadScope) tmp;
+ PRThread *thr;
+
+ thr = PR_CreateThreadGCAble(PR_USER_THREAD,
+ Level_2_Thread,
+ NULL,
+ PR_PRIORITY_HIGH,
+ scope,
+ PR_JOINABLE_THREAD,
+ 0);
+
+ if (!thr) {
+ printf("Could not create thread!\n");
+ } else {
+ printf("Level_1_Thread[0x%lx] created %15s thread 0x%lx\n",
+ PR_GetCurrentThread(),
+ (scope == PR_GLOBAL_THREAD) ?
+ "PR_GLOBAL_THREAD" : "PR_LOCAL_THREAD",
+ thr);
+ PR_JoinThread(thr);
+ }
+ PR_EnterMonitor(mon);
+ alive--;
+ PR_Notify(mon);
+ PR_ExitMonitor(mon);
+ printf("Thread[0x%lx] exiting\n",PR_GetCurrentThread());
+}
+
+static PRStatus PR_CALLBACK print_thread(PRThread *thread, int i, void *arg)
+{
+ PRInt32 words;
+ PRWord *registers;
+
+ printf(
+ "\nprint_thread[0x%lx]: %-20s - i = %ld\n",thread,
+ (PR_GLOBAL_THREAD == PR_GetThreadScope(thread)) ?
+ "PR_GLOBAL_THREAD" : "PR_LOCAL_THREAD", i);
+ registers = PR_GetGCRegisters(thread, 0, (int *)&words);
+ if (registers)
+ printf("Registers R0 = 0x%x R1 = 0x%x R2 = 0x%x R3 = 0x%x\n",
+ registers[0],registers[1],registers[2],registers[3]);
+ printf("Stack Pointer = 0x%lx\n", PR_GetSP(thread));
+ return PR_SUCCESS;
+}
+
+static void Level_0_Thread(PRThreadScope scope1, PRThreadScope scope2)
+{
+ PRThread *thr;
+ PRThread *me = PR_GetCurrentThread();
+ int n;
+ PRInt32 words;
+ PRWord *registers;
+
+ alive = 0;
+ mon = PR_NewMonitor();
+
+ alive = count;
+ for (n=0; n<count; n++) {
+ thr = PR_CreateThreadGCAble(PR_USER_THREAD,
+ Level_1_Thread,
+ (void *)scope2,
+ PR_PRIORITY_NORMAL,
+ scope1,
+ PR_UNJOINABLE_THREAD,
+ 0);
+ if (!thr) {
+ printf("Could not create thread!\n");
+ alive--;
+ }
+ printf("Level_0_Thread[0x%lx] created %15s thread 0x%lx\n",
+ PR_GetCurrentThread(),
+ (scope1 == PR_GLOBAL_THREAD) ?
+ "PR_GLOBAL_THREAD" : "PR_LOCAL_THREAD",
+ thr);
+
+ PR_Sleep(0);
+ }
+ PR_SuspendAll();
+ PR_EnumerateThreads(print_thread, NULL);
+ registers = PR_GetGCRegisters(me, 1, (int *)&words);
+ if (registers)
+ printf("My Registers: R0 = 0x%x R1 = 0x%x R2 = 0x%x R3 = 0x%x\n",
+ registers[0],registers[1],registers[2],registers[3]);
+ printf("My Stack Pointer = 0x%lx\n", PR_GetSP(me));
+ PR_ResumeAll();
+
+ /* Wait for all threads to exit */
+ PR_EnterMonitor(mon);
+ while (alive) {
+ PR_Wait(mon, PR_INTERVAL_NO_TIMEOUT);
+ }
+
+ PR_ExitMonitor(mon);
+ PR_DestroyMonitor(mon);
+}
+
+static void CreateThreadsUU(void)
+{
+ Level_0_Thread(PR_LOCAL_THREAD, PR_LOCAL_THREAD);
+}
+
+static void CreateThreadsUK(void)
+{
+ Level_0_Thread(PR_LOCAL_THREAD, PR_GLOBAL_THREAD);
+}
+
+static void CreateThreadsKU(void)
+{
+ Level_0_Thread(PR_GLOBAL_THREAD, PR_LOCAL_THREAD);
+}
+
+static void CreateThreadsKK(void)
+{
+ Level_0_Thread(PR_GLOBAL_THREAD, PR_GLOBAL_THREAD);
+}
+
+
+int main(int argc, char **argv)
+{
+ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
+ PR_STDIO_INIT();
+
+ if (argc > 1) {
+ count = atoi(argv[1]);
+ } else {
+ count = 5;
+ }
+
+ printf("\n\n%20s%30s\n\n"," ","Suspend_Resume Test");
+ CreateThreadsUU();
+ CreateThreadsUK();
+ CreateThreadsKU();
+ CreateThreadsKK();
+ PR_SetConcurrency(2);
+
+ printf("\n%20s%30s\n\n"," ","Added 2nd CPU\n");
+
+ CreateThreadsUK();
+ CreateThreadsKK();
+ CreateThreadsUU();
+ CreateThreadsKU();
+ PR_Cleanup();
+
+ return 0;
+}
+
diff --git a/nsprpub/pr/tests/switch.c b/nsprpub/pr/tests/switch.c
new file mode 100644
index 0000000000..43db7888fb
--- /dev/null
+++ b/nsprpub/pr/tests/switch.c
@@ -0,0 +1,252 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+** File: switch.c
+** Description: trying to time context switches
+*/
+
+#include "prinit.h"
+#include "prcvar.h"
+#include "prmem.h"
+#include "prinrval.h"
+#include "prlock.h"
+#include "prlog.h"
+#include "prthread.h"
+#include "prprf.h"
+
+#include "plerror.h"
+#include "plgetopt.h"
+
+#include "private/pprio.h"
+
+#include <stdlib.h>
+
+#define INNER_LOOPS 100
+#define DEFAULT_LOOPS 100
+#define DEFAULT_THREADS 10
+
+static PRFileDesc *debug_out = NULL;
+static PRBool debug_mode = PR_FALSE, verbosity = PR_FALSE, failed = PR_FALSE;
+
+typedef struct Shared
+{
+ PRLock *ml;
+ PRCondVar *cv;
+ PRBool twiddle;
+ PRThread *thread;
+ struct Shared *next;
+} Shared;
+
+static void Help(void)
+{
+ debug_out = PR_STDOUT;
+
+ PR_fprintf(
+ debug_out, "Usage: >./switch [-c n] [-t n] [-d] [-v] [-G] [-C n]\n");
+ PR_fprintf(
+ debug_out, "-c n\tloops at thread level (default: %d)\n", DEFAULT_LOOPS);
+ PR_fprintf(
+ debug_out, "-t n\tnumber of threads (default: %d)\n", DEFAULT_THREADS);
+ PR_fprintf(debug_out, "-d\tturn on debugging output (default: FALSE)\n");
+ PR_fprintf(debug_out, "-v\tturn on verbose output (default: FALSE)\n");
+ PR_fprintf(debug_out, "-G\tglobal threads only (default: FALSE)\n");
+ PR_fprintf(debug_out, "-C n\tconcurrency setting (default: 1)\n");
+} /* Help */
+
+static void PR_CALLBACK Notified(void *arg)
+{
+ Shared *shared = (Shared*)arg;
+ PRStatus status = PR_SUCCESS;
+ while (PR_SUCCESS == status)
+ {
+ PR_Lock(shared->ml);
+ while (shared->twiddle && (PR_SUCCESS == status)) {
+ status = PR_WaitCondVar(shared->cv, PR_INTERVAL_NO_TIMEOUT);
+ }
+ if (verbosity) {
+ PR_fprintf(debug_out, "+");
+ }
+ shared->twiddle = PR_TRUE;
+ shared->next->twiddle = PR_FALSE;
+ PR_NotifyCondVar(shared->next->cv);
+ PR_Unlock(shared->ml);
+ }
+} /* Notified */
+
+static Shared home;
+PRIntn PR_CALLBACK Switch(PRIntn argc, char **argv)
+{
+ PLOptStatus os;
+ PRStatus status;
+ PRBool help = PR_FALSE;
+ PRUintn concurrency = 1;
+ Shared *shared, *link;
+ PRIntervalTime timein, timeout;
+ PRThreadScope thread_scope = PR_LOCAL_THREAD;
+ PRUintn thread_count, inner_count, loop_count, average;
+ PRUintn thread_limit = DEFAULT_THREADS, loop_limit = DEFAULT_LOOPS;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "hdvc:t:C:G");
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 'v': /* verbose mode */
+ verbosity = PR_TRUE;
+ case 'd': /* debug mode */
+ debug_mode = PR_TRUE;
+ break;
+ case 'c': /* loop counter */
+ loop_limit = atoi(opt->value);
+ break;
+ case 't': /* thread limit */
+ thread_limit = atoi(opt->value);
+ break;
+ case 'C': /* Concurrency limit */
+ concurrency = atoi(opt->value);
+ break;
+ case 'G': /* global threads only */
+ thread_scope = PR_GLOBAL_THREAD;
+ break;
+ case 'h': /* help message */
+ Help();
+ help = PR_TRUE;
+ break;
+ default:
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ if (help) {
+ return -1;
+ }
+
+ if (PR_TRUE == debug_mode)
+ {
+ debug_out = PR_STDOUT;
+ PR_fprintf(debug_out, "Test parameters\n");
+ PR_fprintf(debug_out, "\tThreads involved: %d\n", thread_limit);
+ PR_fprintf(debug_out, "\tIteration limit: %d\n", loop_limit);
+ PR_fprintf(debug_out, "\tConcurrency: %d\n", concurrency);
+ PR_fprintf(
+ debug_out, "\tThread type: %s\n",
+ (PR_GLOBAL_THREAD == thread_scope) ? "GLOBAL" : "LOCAL");
+ }
+
+ PR_SetConcurrency(concurrency);
+
+ link = &home;
+ home.ml = PR_NewLock();
+ home.cv = PR_NewCondVar(home.ml);
+ home.twiddle = PR_FALSE;
+ home.next = NULL;
+
+ timeout = 0;
+
+ for (thread_count = 1; thread_count <= thread_limit; ++thread_count)
+ {
+ shared = PR_NEWZAP(Shared);
+
+ shared->ml = home.ml;
+ shared->cv = PR_NewCondVar(home.ml);
+ shared->twiddle = PR_TRUE;
+ shared->next = link;
+ link = shared;
+
+ shared->thread = PR_CreateThread(
+ PR_USER_THREAD, Notified, shared,
+ PR_PRIORITY_HIGH, thread_scope,
+ PR_JOINABLE_THREAD, 0);
+ PR_ASSERT(shared->thread != NULL);
+ if (NULL == shared->thread) {
+ failed = PR_TRUE;
+ }
+ }
+
+ for (loop_count = 1; loop_count <= loop_limit; ++loop_count)
+ {
+ timein = PR_IntervalNow();
+ for (inner_count = 0; inner_count < INNER_LOOPS; ++inner_count)
+ {
+ PR_Lock(home.ml);
+ home.twiddle = PR_TRUE;
+ shared->twiddle = PR_FALSE;
+ PR_NotifyCondVar(shared->cv);
+ while (home.twiddle)
+ {
+ status = PR_WaitCondVar(home.cv, PR_INTERVAL_NO_TIMEOUT);
+ if (PR_FAILURE == status) {
+ failed = PR_TRUE;
+ }
+ }
+ PR_Unlock(home.ml);
+ }
+ timeout += (PR_IntervalNow() - timein);
+ }
+
+ if (debug_mode)
+ {
+ average = PR_IntervalToMicroseconds(timeout)
+ / (INNER_LOOPS * loop_limit * thread_count);
+ PR_fprintf(
+ debug_out, "Average switch times %d usecs for %d threads\n",
+ average, thread_limit);
+ }
+
+ link = shared;
+ for (thread_count = 1; thread_count <= thread_limit; ++thread_count)
+ {
+ if (&home == link) {
+ break;
+ }
+ status = PR_Interrupt(link->thread);
+ if (PR_SUCCESS != status)
+ {
+ failed = PR_TRUE;
+ if (debug_mode) {
+ PL_FPrintError(debug_out, "Failed to interrupt");
+ }
+ }
+ link = link->next;
+ }
+
+ for (thread_count = 1; thread_count <= thread_limit; ++thread_count)
+ {
+ link = shared->next;
+ status = PR_JoinThread(shared->thread);
+ if (PR_SUCCESS != status)
+ {
+ failed = PR_TRUE;
+ if (debug_mode) {
+ PL_FPrintError(debug_out, "Failed to join");
+ }
+ }
+ PR_DestroyCondVar(shared->cv);
+ PR_DELETE(shared);
+ if (&home == link) {
+ break;
+ }
+ shared = link;
+ }
+ PR_DestroyCondVar(home.cv);
+ PR_DestroyLock(home.ml);
+
+ PR_fprintf(PR_STDOUT, ((failed) ? "FAILED\n" : "PASSED\n"));
+ return ((failed) ? 1 : 0);
+} /* Switch */
+
+int main(int argc, char **argv)
+{
+ PRIntn result;
+ PR_STDIO_INIT();
+ result = PR_Initialize(Switch, argc, argv, 0);
+ return result;
+} /* main */
+
+/* switch.c */
diff --git a/nsprpub/pr/tests/system.c b/nsprpub/pr/tests/system.c
new file mode 100644
index 0000000000..85b5e2e502
--- /dev/null
+++ b/nsprpub/pr/tests/system.c
@@ -0,0 +1,56 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "prio.h"
+#include "prmem.h"
+#include "prprf.h"
+#include "prsystem.h"
+
+#include "plerror.h"
+
+static char *tag[] =
+{
+ "PR_SI_HOSTNAME",
+ "PR_SI_SYSNAME",
+ "PR_SI_RELEASE",
+ "PR_SI_ARCHITECTURE"
+};
+
+static PRSysInfo Incr(PRSysInfo *cmd)
+{
+ PRIntn tmp = (PRIntn)*cmd + 1;
+ *cmd = (PRSysInfo)tmp;
+ return (PRSysInfo)tmp;
+} /* Incr */
+
+int main(int argc, char **argv)
+{
+ PRStatus rv;
+ PRSysInfo cmd;
+ PRFileDesc *output = PR_GetSpecialFD(PR_StandardOutput);
+
+ char *info = (char*)PR_Calloc(SYS_INFO_BUFFER_LENGTH, 1);
+ for (cmd = PR_SI_HOSTNAME; cmd <= PR_SI_ARCHITECTURE; Incr(&cmd))
+ {
+ rv = PR_GetSystemInfo(cmd, info, SYS_INFO_BUFFER_LENGTH);
+ if (PR_SUCCESS == rv) {
+ PR_fprintf(output, "%s: %s\n", tag[cmd], info);
+ }
+ else {
+ PL_FPrintError(output, tag[cmd]);
+ }
+ }
+ PR_DELETE(info);
+
+ PR_fprintf(output, "Host page size is %d\n", PR_GetPageSize());
+ PR_fprintf(output, "Page shift is %d\n", PR_GetPageShift());
+ PR_fprintf(output, "Memory map alignment is %ld\n", PR_GetMemMapAlignment());
+ PR_fprintf(output, "Number of processors is: %d\n", PR_GetNumberOfProcessors());
+ PR_fprintf(output, "Physical memory size is: %llu\n", PR_GetPhysicalMemorySize());
+
+ return 0;
+} /* main */
+
+/* system.c */
diff --git a/nsprpub/pr/tests/testbit.c b/nsprpub/pr/tests/testbit.c
new file mode 100644
index 0000000000..889c637e22
--- /dev/null
+++ b/nsprpub/pr/tests/testbit.c
@@ -0,0 +1,111 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+** File: lazyinit.c
+** Description: Test the functions and macros declared in prbit.h
+**
+*/
+
+#include "nspr.h"
+
+#define ErrorReport(x) { printf((x)); failed = 1; }
+
+prbitmap_t myMap[512/32] = { 0 };
+
+PRInt32 rc;
+PRInt32 i;
+PRIntn failed = 0;
+
+int main(int argc, char **argv)
+{
+ /*
+ ** Test bitmap things.
+ */
+ if ( PR_TEST_BIT( myMap, 0 )) {
+ ErrorReport("Test 0.0: Failed\n");
+ }
+
+ if ( PR_TEST_BIT( myMap, 31 )) {
+ ErrorReport("Test 0.1: Failed\n");
+ }
+
+ if ( PR_TEST_BIT( myMap, 128 )) {
+ ErrorReport("Test 0.2: Failed\n");
+ }
+
+ if ( PR_TEST_BIT( myMap, 129 )) {
+ ErrorReport("Test 0.3: Failed\n");
+ }
+
+
+ PR_SET_BIT( myMap, 0 );
+ if ( !PR_TEST_BIT( myMap, 0 )) {
+ ErrorReport("Test 1.0: Failed\n");
+ }
+
+ PR_CLEAR_BIT( myMap, 0 );
+ if ( PR_TEST_BIT( myMap, 0 )) {
+ ErrorReport("Test 1.0.1: Failed\n");
+ }
+
+ PR_SET_BIT( myMap, 31 );
+ if ( !PR_TEST_BIT( myMap, 31 )) {
+ ErrorReport("Test 1.1: Failed\n");
+ }
+
+ PR_CLEAR_BIT( myMap, 31 );
+ if ( PR_TEST_BIT( myMap, 31 )) {
+ ErrorReport("Test 1.1.1: Failed\n");
+ }
+
+ PR_SET_BIT( myMap, 128 );
+ if ( !PR_TEST_BIT( myMap, 128 )) {
+ ErrorReport("Test 1.2: Failed\n");
+ }
+
+ PR_CLEAR_BIT( myMap, 128 );
+ if ( PR_TEST_BIT( myMap, 128 )) {
+ ErrorReport("Test 1.2.1: Failed\n");
+ }
+
+ PR_SET_BIT( myMap, 129 );
+ if ( !PR_TEST_BIT( myMap, 129 )) {
+ ErrorReport("Test 1.3: Failed\n");
+ }
+
+ PR_CLEAR_BIT( myMap, 129 );
+ if ( PR_TEST_BIT( myMap, 129 )) {
+ ErrorReport("Test 1.3.1: Failed\n");
+ }
+
+
+ /*
+ ** Test Ceiling and Floor functions and macros
+ */
+ if ((rc = PR_CeilingLog2(32)) != 5 ) {
+ ErrorReport("Test 10.0: Failed\n");
+ }
+
+ if ((rc = PR_FloorLog2(32)) != 5 ) {
+ ErrorReport("Test 10.1: Failed\n");
+ }
+
+
+ /*
+ ** Evaluate results and exit
+ */
+ if (failed)
+ {
+ printf("FAILED\n");
+ return(1);
+ }
+ else
+ {
+ printf("PASSED\n");
+ return(0);
+ }
+} /* end main() */
+/* end testbit.c */
diff --git a/nsprpub/pr/tests/testfile.c b/nsprpub/pr/tests/testfile.c
new file mode 100644
index 0000000000..79d8a05f92
--- /dev/null
+++ b/nsprpub/pr/tests/testfile.c
@@ -0,0 +1,963 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nspr.h"
+#include "prpriv.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef WIN32
+#include <windows.h>
+#include <process.h>
+#endif
+#if defined(_PR_PTHREADS)
+#include <pthread.h>
+#endif
+
+#if defined(XP_UNIX)
+#include <unistd.h>
+#endif
+
+#if defined(XP_OS2)
+#define INCL_DOSFILEMGR
+#include <os2.h>
+#include <getopt.h>
+#include <errno.h>
+#endif /* XP_OS2 */
+
+static int _debug_on = 0;
+
+#ifdef WINCE
+#define setbuf(x,y)
+#endif
+
+#ifdef XP_WIN
+#define mode_t int
+#endif
+
+#define DPRINTF(arg) if (_debug_on) printf arg
+
+PRLock *lock;
+PRMonitor *mon;
+PRInt32 count;
+int thread_count;
+
+#ifdef WIN16
+#define BUF_DATA_SIZE 256 * 120
+#else
+#define BUF_DATA_SIZE 256 * 1024
+#endif
+
+#define NUM_RDWR_THREADS 10
+#define NUM_DIRTEST_THREADS 4
+#define CHUNK_SIZE 512
+
+typedef struct buffer {
+ char data[BUF_DATA_SIZE];
+} buffer;
+
+typedef struct File_Rdwr_Param {
+ char *pathname;
+ char *buf;
+ int offset;
+ int len;
+} File_Rdwr_Param;
+
+#ifdef XP_PC
+#ifdef XP_OS2
+char *TEST_DIR = "prdir";
+#else
+char *TEST_DIR = "C:\\temp\\prdir";
+#endif
+char *FILE_NAME = "pr_testfile";
+char *HIDDEN_FILE_NAME = "hidden_pr_testfile";
+#else
+char *TEST_DIR = "./tmp-testfile_dir";
+char *FILE_NAME = "pr_testfile";
+char *HIDDEN_FILE_NAME = ".hidden_pr_testfile";
+#endif
+buffer *in_buf, *out_buf;
+char pathname[256], renamename[256];
+#ifdef WINCE
+WCHAR wPathname[256];
+#endif
+#define TMPDIR_LEN 64
+char testdir[TMPDIR_LEN];
+static PRInt32 PR_CALLBACK DirTest(void *argunused);
+PRInt32 dirtest_failed = 0;
+
+PRThread* create_new_thread(PRThreadType type,
+ void (*start)(void *arg),
+ void *arg,
+ PRThreadPriority priority,
+ PRThreadScope scope,
+ PRThreadState state,
+ PRUint32 stackSize, PRInt32 index)
+{
+ PRInt32 native_thread = 0;
+
+ PR_ASSERT(state == PR_UNJOINABLE_THREAD);
+
+#if defined(_PR_PTHREADS) || defined(WIN32) || defined(XP_OS2)
+
+ switch(index % 4) {
+ case 0:
+ scope = (PR_LOCAL_THREAD);
+ break;
+ case 1:
+ scope = (PR_GLOBAL_THREAD);
+ break;
+ case 2:
+ scope = (PR_GLOBAL_BOUND_THREAD);
+ break;
+ case 3:
+ native_thread = 1;
+ break;
+ default:
+ PR_NOT_REACHED("Invalid scope");
+ break;
+ }
+ if (native_thread) {
+#if defined(_PR_PTHREADS)
+ pthread_t tid;
+ if (!pthread_create(&tid, NULL, start, arg)) {
+ return((PRThread *) tid);
+ }
+ else {
+ return (NULL);
+ }
+#elif defined(XP_OS2)
+ TID tid;
+
+ tid = (TID)_beginthread((void(* _Optlink)(void*))start,
+ NULL, 32768, arg);
+ if (tid == -1) {
+ printf("_beginthread failed. errno %d\n", errno);
+ return (NULL);
+ }
+ else {
+ return((PRThread *) tid);
+ }
+#else
+ HANDLE thandle;
+ unsigned tid;
+
+ thandle = (HANDLE) _beginthreadex(
+ NULL,
+ stackSize,
+ (unsigned (__stdcall *)(void *))start,
+ arg,
+ STACK_SIZE_PARAM_IS_A_RESERVATION,
+ &tid);
+ return((PRThread *) thandle);
+#endif
+ } else {
+ return(PR_CreateThread(type,start,arg,priority,scope,state,stackSize));
+ }
+#else
+ return(PR_CreateThread(type,start,arg,priority,scope,state,stackSize));
+#endif
+}
+
+static void PR_CALLBACK File_Write(void *arg)
+{
+ PRFileDesc *fd_file;
+ File_Rdwr_Param *fp = (File_Rdwr_Param *) arg;
+ char *name, *buf;
+ int offset, len;
+
+ setbuf(stdout, NULL);
+ name = fp->pathname;
+ buf = fp->buf;
+ offset = fp->offset;
+ len = fp->len;
+
+ fd_file = PR_Open(name, PR_RDWR | PR_CREATE_FILE, 0777);
+ if (fd_file == NULL) {
+ printf("testfile failed to create/open file %s\n",name);
+ return;
+ }
+ if (PR_Seek(fd_file, offset, PR_SEEK_SET) < 0) {
+ printf("testfile failed to seek in file %s\n",name);
+ return;
+ }
+ if ((PR_Write(fd_file, buf, len)) < 0) {
+ printf("testfile failed to write to file %s\n",name);
+ return;
+ }
+ DPRINTF(("Write out_buf[0] = 0x%x\n",(*((int *) buf))));
+ PR_Close(fd_file);
+ PR_DELETE(fp);
+
+ PR_EnterMonitor(mon);
+ --thread_count;
+ PR_Notify(mon);
+ PR_ExitMonitor(mon);
+}
+
+static void PR_CALLBACK File_Read(void *arg)
+{
+ PRFileDesc *fd_file;
+ File_Rdwr_Param *fp = (File_Rdwr_Param *) arg;
+ char *name, *buf;
+ int offset, len;
+
+ setbuf(stdout, NULL);
+ name = fp->pathname;
+ buf = fp->buf;
+ offset = fp->offset;
+ len = fp->len;
+
+ fd_file = PR_Open(name, PR_RDONLY, 0);
+ if (fd_file == NULL) {
+ printf("testfile failed to open file %s\n",name);
+ return;
+ }
+ if (PR_Seek(fd_file, offset, PR_SEEK_SET) < 0) {
+ printf("testfile failed to seek in file %s\n",name);
+ return;
+ }
+ if ((PR_Read(fd_file, buf, len)) < 0) {
+ printf("testfile failed to read to file %s\n",name);
+ return;
+ }
+ DPRINTF(("Read in_buf[0] = 0x%x\n",(*((int *) buf))));
+ PR_Close(fd_file);
+ PR_DELETE(fp);
+
+ PR_EnterMonitor(mon);
+ --thread_count;
+ PR_Notify(mon);
+ PR_ExitMonitor(mon);
+}
+
+
+static PRInt32 Misc_File_Tests(char *pathname)
+{
+ PRFileDesc *fd_file;
+ int len, rv = 0;
+ PRFileInfo file_info, file_info1;
+ char tmpname[1024];
+
+ setbuf(stdout, NULL);
+ /*
+ * Test PR_Available, PR_Seek, PR_GetFileInfo, PR_Rename, PR_Access
+ */
+
+ fd_file = PR_Open(pathname, PR_RDWR | PR_CREATE_FILE, 0777);
+
+ if (fd_file == NULL) {
+ printf("testfile failed to create/open file %s\n",pathname);
+ return -1;
+ }
+ if (PR_GetOpenFileInfo(fd_file, &file_info) < 0) {
+ printf("testfile PR_GetFileInfo failed on file %s\n",pathname);
+ rv = -1;
+ goto cleanup;
+ }
+ if (PR_Access(pathname, PR_ACCESS_EXISTS) != 0) {
+ printf("testfile PR_Access failed on file %s\n",pathname);
+ rv = -1;
+ goto cleanup;
+ }
+ if (PR_Access(pathname, PR_ACCESS_WRITE_OK) != 0) {
+ printf("testfile PR_Access failed on file %s\n",pathname);
+ rv = -1;
+ goto cleanup;
+ }
+ if (PR_Access(pathname, PR_ACCESS_READ_OK) != 0) {
+ printf("testfile PR_Access failed on file %s\n",pathname);
+ rv = -1;
+ goto cleanup;
+ }
+
+
+ if (PR_GetFileInfo(pathname, &file_info) < 0) {
+ printf("testfile PR_GetFileInfo failed on file %s\n",pathname);
+ rv = -1;
+ goto cleanup;
+ }
+ if (file_info.type != PR_FILE_FILE) {
+ printf(
+ "testfile: Error - PR_GetFileInfo returned incorrect type for file %s\n",
+ pathname);
+ rv = -1;
+ goto cleanup;
+ }
+ if (file_info.size != 0) {
+ printf(
+ "testfile PR_GetFileInfo returned incorrect size (%d should be 0) for file %s\n",
+ file_info.size, pathname);
+ rv = -1;
+ goto cleanup;
+ }
+ file_info1 = file_info;
+
+ len = PR_Available(fd_file);
+ if (len < 0) {
+ printf("testfile PR_Available failed on file %s\n",pathname);
+ rv = -1;
+ goto cleanup;
+ } else if (len != 0) {
+ printf(
+ "testfile PR_Available failed: expected/returned = %d/%d bytes\n",
+ 0, len);
+ rv = -1;
+ goto cleanup;
+ }
+ if (PR_GetOpenFileInfo(fd_file, &file_info) < 0) {
+ printf("testfile PR_GetFileInfo failed on file %s\n",pathname);
+ goto cleanup;
+ }
+ if (LL_NE(file_info.creationTime, file_info1.creationTime)) {
+ printf(
+ "testfile PR_GetFileInfo returned incorrect status-change time: %s\n",
+ pathname);
+ printf("ft = %lld, ft1 = %lld\n",file_info.creationTime,
+ file_info1.creationTime);
+ rv = -1;
+ goto cleanup;
+ }
+ len = PR_Write(fd_file, out_buf->data, CHUNK_SIZE);
+ if (len < 0) {
+ printf("testfile failed to write to file %s\n",pathname);
+ rv = -1;
+ goto cleanup;
+ }
+ if (PR_GetOpenFileInfo(fd_file, &file_info) < 0) {
+ printf("testfile PR_GetFileInfo failed on file %s\n",pathname);
+ goto cleanup;
+ }
+ if (file_info.size != CHUNK_SIZE) {
+ printf(
+ "testfile PR_GetFileInfo returned incorrect size (%d should be %d) for file %s\n",
+ file_info.size, CHUNK_SIZE, pathname);
+ rv = -1;
+ goto cleanup;
+ }
+ if (LL_CMP(file_info.modifyTime, <, file_info1.modifyTime)) {
+ printf(
+ "testfile PR_GetFileInfo returned incorrect modify time: %s\n",
+ pathname);
+ printf("ft = %lld, ft1 = %lld\n",file_info.modifyTime,
+ file_info1.modifyTime);
+ rv = -1;
+ goto cleanup;
+ }
+
+ len = PR_Available(fd_file);
+ if (len < 0) {
+ printf("testfile PR_Available failed on file %s\n",pathname);
+ rv = -1;
+ goto cleanup;
+ } else if (len != 0) {
+ printf(
+ "testfile PR_Available failed: expected/returned = %d/%d bytes\n",
+ 0, len);
+ rv = -1;
+ goto cleanup;
+ }
+
+ PR_Seek(fd_file, 0, PR_SEEK_SET);
+ len = PR_Available(fd_file);
+ if (len < 0) {
+ printf("testfile PR_Available failed on file %s\n",pathname);
+ rv = -1;
+ goto cleanup;
+ } else if (len != CHUNK_SIZE) {
+ printf(
+ "testfile PR_Available failed: expected/returned = %d/%d bytes\n",
+ CHUNK_SIZE, len);
+ rv = -1;
+ goto cleanup;
+ }
+ PR_Close(fd_file);
+
+ strcpy(tmpname,pathname);
+ strcat(tmpname,".RENAMED");
+ if (PR_FAILURE == PR_Rename(pathname, tmpname)) {
+ printf("testfile failed to rename file %s\n",pathname);
+ rv = -1;
+ goto cleanup;
+ }
+
+ fd_file = PR_Open(pathname, PR_RDWR | PR_CREATE_FILE, 0777);
+ len = PR_Write(fd_file, out_buf->data, CHUNK_SIZE);
+ PR_Close(fd_file);
+ if (PR_SUCCESS == PR_Rename(pathname, tmpname)) {
+ printf("testfile renamed to existing file %s\n",pathname);
+ }
+
+ if ((PR_Delete(tmpname)) < 0) {
+ printf("testfile failed to unlink file %s\n",tmpname);
+ rv = -1;
+ }
+
+cleanup:
+ if ((PR_Delete(pathname)) < 0) {
+ printf("testfile failed to unlink file %s\n",pathname);
+ rv = -1;
+ }
+ return rv;
+}
+
+
+static PRInt32 PR_CALLBACK FileTest(void)
+{
+ PRDir *fd_dir;
+ int i, offset, len, rv = 0;
+ PRThread *t;
+ PRThreadScope scope = PR_GLOBAL_THREAD;
+ File_Rdwr_Param *fparamp;
+
+ /*
+ * Create Test dir
+ */
+ if ((PR_MkDir(TEST_DIR, 0777)) < 0) {
+ printf("testfile failed to create dir %s\n",TEST_DIR);
+ return -1;
+ }
+ fd_dir = PR_OpenDir(TEST_DIR);
+ if (fd_dir == NULL) {
+ printf("testfile failed to open dir %s\n",TEST_DIR);
+ rv = -1;
+ goto cleanup;
+ }
+
+ PR_CloseDir(fd_dir);
+
+ strcat(pathname, TEST_DIR);
+ strcat(pathname, "/");
+ strcat(pathname, FILE_NAME);
+
+ in_buf = PR_NEW(buffer);
+ if (in_buf == NULL) {
+ printf(
+ "testfile failed to alloc buffer struct\n");
+ rv = -1;
+ goto cleanup;
+ }
+ out_buf = PR_NEW(buffer);
+ if (out_buf == NULL) {
+ printf(
+ "testfile failed to alloc buffer struct\n");
+ rv = -1;
+ goto cleanup;
+ }
+
+ /*
+ * Start a bunch of writer threads
+ */
+ offset = 0;
+ len = CHUNK_SIZE;
+ PR_EnterMonitor(mon);
+ for (i = 0; i < NUM_RDWR_THREADS; i++) {
+ fparamp = PR_NEW(File_Rdwr_Param);
+ if (fparamp == NULL) {
+ printf(
+ "testfile failed to alloc File_Rdwr_Param struct\n");
+ rv = -1;
+ goto cleanup;
+ }
+ fparamp->pathname = pathname;
+ fparamp->buf = out_buf->data + offset;
+ fparamp->offset = offset;
+ fparamp->len = len;
+ memset(fparamp->buf, i, len);
+
+ t = create_new_thread(PR_USER_THREAD,
+ File_Write, (void *)fparamp,
+ PR_PRIORITY_NORMAL,
+ scope,
+ PR_UNJOINABLE_THREAD,
+ 0, i);
+ offset += len;
+ }
+ thread_count = i;
+ /* Wait for writer threads to exit */
+ while (thread_count) {
+ PR_Wait(mon, PR_INTERVAL_NO_TIMEOUT);
+ }
+ PR_ExitMonitor(mon);
+
+
+ /*
+ * Start a bunch of reader threads
+ */
+ offset = 0;
+ len = CHUNK_SIZE;
+ PR_EnterMonitor(mon);
+ for (i = 0; i < NUM_RDWR_THREADS; i++) {
+ fparamp = PR_NEW(File_Rdwr_Param);
+ if (fparamp == NULL) {
+ printf(
+ "testfile failed to alloc File_Rdwr_Param struct\n");
+ rv = -1;
+ goto cleanup;
+ }
+ fparamp->pathname = pathname;
+ fparamp->buf = in_buf->data + offset;
+ fparamp->offset = offset;
+ fparamp->len = len;
+
+ t = create_new_thread(PR_USER_THREAD,
+ File_Read, (void *)fparamp,
+ PR_PRIORITY_NORMAL,
+ scope,
+ PR_UNJOINABLE_THREAD,
+ 0, i);
+ offset += len;
+ if ((offset + len) > BUF_DATA_SIZE) {
+ break;
+ }
+ }
+ thread_count = i;
+
+ /* Wait for reader threads to exit */
+ while (thread_count) {
+ PR_Wait(mon, PR_INTERVAL_NO_TIMEOUT);
+ }
+ PR_ExitMonitor(mon);
+
+ if (memcmp(in_buf->data, out_buf->data, offset) != 0) {
+ printf("File Test failed: file data corrupted\n");
+ rv = -1;
+ goto cleanup;
+ }
+
+ if ((PR_Delete(pathname)) < 0) {
+ printf("testfile failed to unlink file %s\n",pathname);
+ rv = -1;
+ goto cleanup;
+ }
+
+ /*
+ * Test PR_Available, PR_Seek, PR_GetFileInfo, PR_Rename, PR_Access
+ */
+ if (Misc_File_Tests(pathname) < 0) {
+ rv = -1;
+ }
+
+cleanup:
+ if ((PR_RmDir(TEST_DIR)) < 0) {
+ printf("testfile failed to rmdir %s\n", TEST_DIR);
+ rv = -1;
+ }
+ return rv;
+}
+
+struct dirtest_arg {
+ PRMonitor *mon;
+ PRInt32 done;
+};
+
+static PRInt32 RunDirTest(void)
+{
+ int i;
+ PRThread *t;
+ PRMonitor *mon;
+ struct dirtest_arg thrarg;
+
+ mon = PR_NewMonitor();
+ if (!mon) {
+ printf("RunDirTest: Error - failed to create monitor\n");
+ dirtest_failed = 1;
+ return -1;
+ }
+ thrarg.mon = mon;
+
+ for (i = 0; i < NUM_DIRTEST_THREADS; i++) {
+
+ thrarg.done= 0;
+ t = create_new_thread(PR_USER_THREAD,
+ DirTest, &thrarg,
+ PR_PRIORITY_NORMAL,
+ PR_LOCAL_THREAD,
+ PR_UNJOINABLE_THREAD,
+ 0, i);
+ if (!t) {
+ printf("RunDirTest: Error - failed to create thread\n");
+ dirtest_failed = 1;
+ return -1;
+ }
+ PR_EnterMonitor(mon);
+ while (!thrarg.done) {
+ PR_Wait(mon, PR_INTERVAL_NO_TIMEOUT);
+ }
+ PR_ExitMonitor(mon);
+
+ }
+ PR_DestroyMonitor(mon);
+ return 0;
+}
+
+static PRInt32 PR_CALLBACK DirTest(void *arg)
+{
+ struct dirtest_arg *tinfo = (struct dirtest_arg *) arg;
+ PRFileDesc *fd_file;
+ PRDir *fd_dir;
+ int i;
+ int path_len;
+ PRDirEntry *dirEntry;
+ PRFileInfo info;
+ PRInt32 num_files = 0;
+#if defined(XP_PC) && defined(WIN32)
+ HANDLE hfile;
+#endif
+
+#define FILES_IN_DIR 20
+
+ /*
+ * Create Test dir
+ */
+ DPRINTF(("Creating test dir %s\n",TEST_DIR));
+ if ((PR_MkDir(TEST_DIR, 0777)) < 0) {
+ printf(
+ "testfile failed to create dir %s [%d, %d]\n",
+ TEST_DIR, PR_GetError(), PR_GetOSError());
+ return -1;
+ }
+ fd_dir = PR_OpenDir(TEST_DIR);
+ if (fd_dir == NULL) {
+ printf(
+ "testfile failed to open dirctory %s [%d, %d]\n",
+ TEST_DIR, PR_GetError(), PR_GetOSError());
+ return -1;
+ }
+
+ strcpy(pathname, TEST_DIR);
+ strcat(pathname, "/");
+ strcat(pathname, FILE_NAME);
+ path_len = strlen(pathname);
+
+ for (i = 0; i < FILES_IN_DIR; i++) {
+
+ sprintf(pathname + path_len,"%d%s",i,"");
+
+ DPRINTF(("Creating test file %s\n",pathname));
+
+ fd_file = PR_Open(pathname, PR_RDWR | PR_CREATE_FILE, 0777);
+
+ if (fd_file == NULL) {
+ printf(
+ "testfile failed to create/open file %s [%d, %d]\n",
+ pathname, PR_GetError(), PR_GetOSError());
+ return -1;
+ }
+ PR_Close(fd_file);
+ }
+#if defined(XP_UNIX) || (defined(XP_PC) && defined(WIN32)) || defined(XP_OS2)
+ /*
+ * Create a hidden file - a platform-dependent operation
+ */
+ strcpy(pathname, TEST_DIR);
+ strcat(pathname, "/");
+ strcat(pathname, HIDDEN_FILE_NAME);
+#if defined(XP_UNIX)
+ DPRINTF(("Creating hidden test file %s\n",pathname));
+ fd_file = PR_Open(pathname, PR_RDWR | PR_CREATE_FILE, 0777);
+
+ if (fd_file == NULL) {
+ printf(
+ "testfile failed to create/open hidden file %s [%d, %d]\n",
+ pathname, PR_GetError(), PR_GetOSError());
+ return -1;
+ }
+
+ PR_Close(fd_file);
+
+#elif defined(WINCE)
+ DPRINTF(("Creating hidden test file %s\n",pathname));
+ MultiByteToWideChar(CP_ACP, 0, pathname, -1, wPathname, 256);
+ hfile = CreateFile(wPathname, GENERIC_READ,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ NULL,
+ CREATE_NEW,
+ FILE_ATTRIBUTE_HIDDEN,
+ NULL);
+ if (hfile == INVALID_HANDLE_VALUE) {
+ printf("testfile failed to create/open hidden file %s [0, %d]\n",
+ pathname, GetLastError());
+ return -1;
+ }
+ CloseHandle(hfile);
+
+#elif defined(XP_PC) && defined(WIN32)
+ DPRINTF(("Creating hidden test file %s\n",pathname));
+ hfile = CreateFile(pathname, GENERIC_READ,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ NULL,
+ CREATE_NEW,
+ FILE_ATTRIBUTE_HIDDEN,
+ NULL);
+ if (hfile == INVALID_HANDLE_VALUE) {
+ printf("testfile failed to create/open hidden file %s [0, %d]\n",
+ pathname, GetLastError());
+ return -1;
+ }
+ CloseHandle(hfile);
+
+#elif defined(OS2)
+ DPRINTF(("Creating hidden test file %s\n",pathname));
+ fd_file = PR_Open(pathname, PR_RDWR | PR_CREATE_FILE, (int)FILE_HIDDEN);
+
+ if (fd_file == NULL) {
+ printf("testfile failed to create/open hidden file %s [%d, %d]\n",
+ pathname, PR_GetError(), PR_GetOSError());
+ return -1;
+ }
+ PR_Close(fd_file);
+#endif /* XP_UNIX */
+
+#endif /* XP_UNIX || (XP_PC && WIN32) */
+
+
+ if (PR_FAILURE == PR_CloseDir(fd_dir))
+ {
+ printf(
+ "testfile failed to close dirctory %s [%d, %d]\n",
+ TEST_DIR, PR_GetError(), PR_GetOSError());
+ return -1;
+ }
+ fd_dir = PR_OpenDir(TEST_DIR);
+ if (fd_dir == NULL) {
+ printf(
+ "testfile failed to reopen dirctory %s [%d, %d]\n",
+ TEST_DIR, PR_GetError(), PR_GetOSError());
+ return -1;
+ }
+
+ /*
+ * List all files, including hidden files
+ */
+ DPRINTF(("Listing all files in directory %s\n",TEST_DIR));
+#if defined(XP_UNIX) || (defined(XP_PC) && defined(WIN32)) || defined(XP_OS2)
+ num_files = FILES_IN_DIR + 1;
+#else
+ num_files = FILES_IN_DIR;
+#endif
+ while ((dirEntry = PR_ReadDir(fd_dir, PR_SKIP_BOTH)) != NULL) {
+ num_files--;
+ strcpy(pathname, TEST_DIR);
+ strcat(pathname, "/");
+ strcat(pathname, dirEntry->name);
+ DPRINTF(("\t%s\n",dirEntry->name));
+
+ if ((PR_GetFileInfo(pathname, &info)) < 0) {
+ printf(
+ "testfile failed to GetFileInfo file %s [%d, %d]\n",
+ pathname, PR_GetError(), PR_GetOSError());
+ return -1;
+ }
+
+ if (info.type != PR_FILE_FILE) {
+ printf(
+ "testfile incorrect fileinfo for file %s [%d, %d]\n",
+ pathname, PR_GetError(), PR_GetOSError());
+ return -1;
+ }
+ }
+ if (num_files != 0)
+ {
+ printf(
+ "testfile failed to find all files in directory %s [%d, %d]\n",
+ TEST_DIR, PR_GetError(), PR_GetOSError());
+ return -1;
+ }
+
+ PR_CloseDir(fd_dir);
+
+#if defined(XP_UNIX) || (defined(XP_PC) && defined(WIN32)) || defined(XP_OS2)
+
+ /*
+ * List all files, except hidden files
+ */
+
+ fd_dir = PR_OpenDir(TEST_DIR);
+ if (fd_dir == NULL) {
+ printf(
+ "testfile failed to reopen dirctory %s [%d, %d]\n",
+ TEST_DIR, PR_GetError(), PR_GetOSError());
+ return -1;
+ }
+
+ DPRINTF(("Listing non-hidden files in directory %s\n",TEST_DIR));
+ while ((dirEntry = PR_ReadDir(fd_dir, PR_SKIP_HIDDEN)) != NULL) {
+ DPRINTF(("\t%s\n",dirEntry->name));
+ if (!strcmp(HIDDEN_FILE_NAME, dirEntry->name)) {
+ printf("testfile found hidden file %s\n", pathname);
+ return -1;
+ }
+
+ }
+ /*
+ * Delete hidden file
+ */
+ strcpy(pathname, TEST_DIR);
+ strcat(pathname, "/");
+ strcat(pathname, HIDDEN_FILE_NAME);
+ if (PR_FAILURE == PR_Delete(pathname)) {
+ printf(
+ "testfile failed to delete hidden file %s [%d, %d]\n",
+ pathname, PR_GetError(), PR_GetOSError());
+ return -1;
+ }
+
+ PR_CloseDir(fd_dir);
+#endif /* XP_UNIX || (XP_PC && WIN32) */
+
+ strcpy(renamename, TEST_DIR);
+ strcat(renamename, ".RENAMED");
+ if (PR_FAILURE == PR_Rename(TEST_DIR, renamename)) {
+ printf(
+ "testfile failed to rename directory %s [%d, %d]\n",
+ TEST_DIR, PR_GetError(), PR_GetOSError());
+ return -1;
+ }
+
+ if (PR_FAILURE == PR_MkDir(TEST_DIR, 0777)) {
+ printf(
+ "testfile failed to recreate dir %s [%d, %d]\n",
+ TEST_DIR, PR_GetError(), PR_GetOSError());
+ return -1;
+ }
+ if (PR_SUCCESS == PR_Rename(renamename, TEST_DIR)) {
+ printf(
+ "testfile renamed directory to existing name %s\n",
+ renamename);
+ return -1;
+ }
+
+ if (PR_FAILURE == PR_RmDir(TEST_DIR)) {
+ printf(
+ "testfile failed to rmdir %s [%d, %d]\n",
+ TEST_DIR, PR_GetError(), PR_GetOSError());
+ return -1;
+ }
+
+ if (PR_FAILURE == PR_Rename(renamename, TEST_DIR)) {
+ printf(
+ "testfile failed to rename directory %s [%d, %d]\n",
+ renamename, PR_GetError(), PR_GetOSError());
+ return -1;
+ }
+ fd_dir = PR_OpenDir(TEST_DIR);
+ if (fd_dir == NULL) {
+ printf(
+ "testfile failed to reopen directory %s [%d, %d]\n",
+ TEST_DIR, PR_GetError(), PR_GetOSError());
+ return -1;
+ }
+
+ strcpy(pathname, TEST_DIR);
+ strcat(pathname, "/");
+ strcat(pathname, FILE_NAME);
+ path_len = strlen(pathname);
+
+ for (i = 0; i < FILES_IN_DIR; i++) {
+
+ sprintf(pathname + path_len,"%d%s",i,"");
+
+ if (PR_FAILURE == PR_Delete(pathname)) {
+ printf(
+ "testfile failed to delete file %s [%d, %d]\n",
+ pathname, PR_GetError(), PR_GetOSError());
+ return -1;
+ }
+ }
+
+ PR_CloseDir(fd_dir);
+
+ if (PR_FAILURE == PR_RmDir(TEST_DIR)) {
+ printf(
+ "testfile failed to rmdir %s [%d, %d]\n",
+ TEST_DIR, PR_GetError(), PR_GetOSError());
+ return -1;
+ }
+ PR_EnterMonitor(tinfo->mon);
+ tinfo->done = 1;
+ PR_Notify(tinfo->mon);
+ PR_ExitMonitor(tinfo->mon);
+
+ return 0;
+}
+/************************************************************************/
+
+/*
+ * Test file and directory NSPR APIs
+ */
+
+int main(int argc, char **argv)
+{
+#ifdef WIN32
+ PRUint32 len;
+#endif
+#if defined(XP_UNIX) || defined(XP_OS2)
+ int opt;
+ extern char *optarg;
+ extern int optind;
+#endif
+#if defined(XP_UNIX) || defined(XP_OS2)
+ while ((opt = getopt(argc, argv, "d")) != EOF) {
+ switch(opt) {
+ case 'd':
+ _debug_on = 1;
+ break;
+ default:
+ break;
+ }
+ }
+#endif
+ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
+ PR_STDIO_INIT();
+
+ mon = PR_NewMonitor();
+ if (mon == NULL) {
+ printf("testfile: PR_NewMonitor failed\n");
+ exit(2);
+ }
+#ifdef WIN32
+
+#ifdef WINCE
+ {
+ WCHAR tdir[TMPDIR_LEN];
+ len = GetTempPath(TMPDIR_LEN, tdir);
+ if ((len > 0) && (len < (TMPDIR_LEN - 6))) {
+ /*
+ * enough space for prdir
+ */
+ WideCharToMultiByte(CP_ACP, 0, tdir, -1, testdir, TMPDIR_LEN, 0, 0);
+ }
+ }
+#else
+ len = GetTempPath(TMPDIR_LEN, testdir);
+#endif /* WINCE */
+
+ if ((len > 0) && (len < (TMPDIR_LEN - 6))) {
+ /*
+ * enough space for prdir
+ */
+ strcpy((testdir + len),"prdir");
+ TEST_DIR = testdir;
+ printf("TEST_DIR = %s\n",TEST_DIR);
+ }
+#endif /* WIN32 */
+
+ if (FileTest() < 0) {
+ printf("File Test failed\n");
+ exit(2);
+ }
+ printf("File Test passed\n");
+ if ((RunDirTest() < 0) || dirtest_failed) {
+ printf("Dir Test failed\n");
+ exit(2);
+ }
+ printf("Dir Test passed\n");
+
+ PR_DestroyMonitor(mon);
+ PR_Cleanup();
+ return 0;
+}
diff --git a/nsprpub/pr/tests/threads.c b/nsprpub/pr/tests/threads.c
new file mode 100644
index 0000000000..4a28dc6e58
--- /dev/null
+++ b/nsprpub/pr/tests/threads.c
@@ -0,0 +1,211 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nspr.h"
+#include "prinrval.h"
+#include "plgetopt.h"
+#include "pprthred.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+PRMonitor *mon;
+PRInt32 count, iterations, alive;
+
+PRBool debug_mode = PR_FALSE, passed = PR_TRUE;
+
+void
+PR_CALLBACK
+ReallyDumbThread(void *arg)
+{
+ return;
+}
+
+void
+PR_CALLBACK
+DumbThread(void *arg)
+{
+ PRInt32 tmp = (PRInt32)arg;
+ PRThreadScope scope = (PRThreadScope)tmp;
+ PRThread *thr;
+
+ thr = PR_CreateThread(PR_USER_THREAD,
+ ReallyDumbThread,
+ NULL,
+ PR_PRIORITY_NORMAL,
+ scope,
+ PR_JOINABLE_THREAD,
+ 0);
+
+ if (!thr) {
+ if (debug_mode) {
+ printf("Could not create really dumb thread (%d, %d)!\n",
+ PR_GetError(), PR_GetOSError());
+ }
+ passed = PR_FALSE;
+ } else {
+ PR_JoinThread(thr);
+ }
+ PR_EnterMonitor(mon);
+ alive--;
+ PR_Notify(mon);
+ PR_ExitMonitor(mon);
+}
+
+static void CreateThreads(PRThreadScope scope1, PRThreadScope scope2)
+{
+ PRThread *thr;
+ int n;
+
+ alive = 0;
+ mon = PR_NewMonitor();
+
+ alive = count;
+ for (n=0; n<count; n++) {
+ thr = PR_CreateThread(PR_USER_THREAD,
+ DumbThread,
+ (void *)scope2,
+ PR_PRIORITY_NORMAL,
+ scope1,
+ PR_UNJOINABLE_THREAD,
+ 0);
+ if (!thr) {
+ if (debug_mode) {
+ printf("Could not create dumb thread (%d, %d)!\n",
+ PR_GetError(), PR_GetOSError());
+ }
+ passed = PR_FALSE;
+ alive--;
+ }
+
+ PR_Sleep(0);
+ }
+
+ /* Wait for all threads to exit */
+ PR_EnterMonitor(mon);
+ while (alive) {
+ PR_Wait(mon, PR_INTERVAL_NO_TIMEOUT);
+ }
+
+ PR_ExitMonitor(mon);
+ PR_DestroyMonitor(mon);
+}
+
+static void CreateThreadsUU(void)
+{
+ CreateThreads(PR_LOCAL_THREAD, PR_LOCAL_THREAD);
+}
+
+static void CreateThreadsUK(void)
+{
+ CreateThreads(PR_LOCAL_THREAD, PR_GLOBAL_THREAD);
+}
+
+static void CreateThreadsKU(void)
+{
+ CreateThreads(PR_GLOBAL_THREAD, PR_LOCAL_THREAD);
+}
+
+static void CreateThreadsKK(void)
+{
+ CreateThreads(PR_GLOBAL_THREAD, PR_GLOBAL_THREAD);
+}
+
+/************************************************************************/
+
+static void Measure(void (*func)(void), const char *msg)
+{
+ PRIntervalTime start, stop;
+ double d;
+
+ start = PR_IntervalNow();
+ (*func)();
+ stop = PR_IntervalNow();
+
+ if (debug_mode)
+ {
+ d = (double)PR_IntervalToMicroseconds(stop - start);
+ printf("%40s: %6.2f usec\n", msg, d / count);
+ }
+}
+
+int main(int argc, char **argv)
+{
+ int index;
+
+ PR_STDIO_INIT();
+ PR_Init(PR_USER_THREAD, PR_PRIORITY_HIGH, 0);
+
+ {
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "dc:i:");
+ 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 counter */
+ count = atoi(opt->value);
+ break;
+ case 'i': /* loop counter */
+ iterations = atoi(opt->value);
+ break;
+ default:
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+ }
+
+ if (0 == count) {
+ count = 50;
+ }
+ if (0 == iterations) {
+ iterations = 10;
+ }
+
+ if (debug_mode)
+ {
+ printf("\
+** Tests lots of thread creations. \n\
+** Create %ld native threads %ld times. \n\
+** Create %ld user threads %ld times \n", iterations,count,iterations,count);
+ }
+
+ for (index=0; index<iterations; index++) {
+ Measure(CreateThreadsUU, "Create user/user threads");
+ Measure(CreateThreadsUK, "Create user/native threads");
+ Measure(CreateThreadsKU, "Create native/user threads");
+ Measure(CreateThreadsKK, "Create native/native threads");
+ }
+
+ if (debug_mode) {
+ printf("\nNow switch to recycling threads \n\n");
+ }
+ PR_SetThreadRecycleMode(1);
+
+ for (index=0; index<iterations; index++) {
+ Measure(CreateThreadsUU, "Create user/user threads");
+ Measure(CreateThreadsUK, "Create user/native threads");
+ Measure(CreateThreadsKU, "Create native/user threads");
+ Measure(CreateThreadsKK, "Create native/native threads");
+ }
+
+
+ printf("%s\n", ((passed) ? "PASS" : "FAIL"));
+
+ PR_Cleanup();
+
+ if (passed) {
+ return 0;
+ } else {
+ return 1;
+ }
+}
diff --git a/nsprpub/pr/tests/thrpool_client.c b/nsprpub/pr/tests/thrpool_client.c
new file mode 100644
index 0000000000..2c01a3c51d
--- /dev/null
+++ b/nsprpub/pr/tests/thrpool_client.c
@@ -0,0 +1,349 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/***********************************************************************
+**
+** Name: thrpool_client.c
+**
+** Description: Test threadpool functionality.
+**
+** Modification History:
+*/
+#include "primpl.h"
+
+#include "plgetopt.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#ifdef XP_UNIX
+#include <sys/mman.h>
+#endif
+#if defined(_PR_PTHREADS)
+#include <pthread.h>
+#endif
+
+#ifdef WIN32
+#include <process.h>
+#endif
+
+static int _debug_on = 0;
+static int server_port = -1;
+static char *program_name = NULL;
+
+#include "obsolete/prsem.h"
+
+#ifdef XP_PC
+#define mode_t int
+#endif
+
+#define DPRINTF(arg) if (_debug_on) printf arg
+
+#define BUF_DATA_SIZE (2 * 1024)
+#define TCP_MESG_SIZE 1024
+#define NUM_TCP_CLIENTS 10 /* for a listen queue depth of 5 */
+
+#define NUM_TCP_CONNECTIONS_PER_CLIENT 10
+#define NUM_TCP_MESGS_PER_CONNECTION 10
+#define TCP_SERVER_PORT 10000
+
+static PRInt32 num_tcp_clients = NUM_TCP_CLIENTS;
+static PRInt32 num_tcp_connections_per_client = NUM_TCP_CONNECTIONS_PER_CLIENT;
+static PRInt32 tcp_mesg_size = TCP_MESG_SIZE;
+static PRInt32 num_tcp_mesgs_per_connection = NUM_TCP_MESGS_PER_CONNECTION;
+
+int failed_already=0;
+
+typedef struct buffer {
+ char data[BUF_DATA_SIZE];
+} buffer;
+
+PRNetAddr tcp_server_addr, udp_server_addr;
+
+typedef struct Client_Param {
+ PRNetAddr server_addr;
+ PRMonitor *exit_mon; /* monitor to signal on exit */
+ PRInt32 *exit_counter; /* counter to decrement, before exit */
+ PRInt32 datalen;
+} Client_Param;
+
+/*
+ * readn
+ * read data from sockfd into buf
+ */
+static PRInt32
+readn(PRFileDesc *sockfd, char *buf, int len)
+{
+ int rem;
+ int bytes;
+ int offset = 0;
+ PRIntervalTime timeout = PR_INTERVAL_NO_TIMEOUT;
+
+ for (rem=len; rem; offset += bytes, rem -= bytes) {
+ DPRINTF(("thread = 0x%lx: calling PR_Recv, bytes = %d\n",
+ PR_GetCurrentThread(), rem));
+ bytes = PR_Recv(sockfd, buf + offset, rem, 0,
+ timeout);
+ DPRINTF(("thread = 0x%lx: returning from PR_Recv, bytes = %d\n",
+ PR_GetCurrentThread(), bytes));
+ if (bytes < 0) {
+ return -1;
+ }
+ }
+ return len;
+}
+
+/*
+ * writen
+ * write data from buf to sockfd
+ */
+static PRInt32
+writen(PRFileDesc *sockfd, char *buf, int len)
+{
+ int rem;
+ int bytes;
+ int offset = 0;
+
+ for (rem=len; rem; offset += bytes, rem -= bytes) {
+ DPRINTF(("thread = 0x%lx: calling PR_Send, bytes = %d\n",
+ PR_GetCurrentThread(), rem));
+ bytes = PR_Send(sockfd, buf + offset, rem, 0,
+ PR_INTERVAL_NO_TIMEOUT);
+ DPRINTF(("thread = 0x%lx: returning from PR_Send, bytes = %d\n",
+ PR_GetCurrentThread(), bytes));
+ if (bytes <= 0) {
+ return -1;
+ }
+ }
+ return len;
+}
+
+/*
+ * TCP_Client
+ * Client job
+ * Connect to the server at the address specified in the argument.
+ * Fill in a buffer, write data to server, read it back and check
+ * for data corruption.
+ * Close the socket for server connection
+ */
+static void PR_CALLBACK
+TCP_Client(void *arg)
+{
+ Client_Param *cp = (Client_Param *) arg;
+ PRFileDesc *sockfd;
+ buffer *in_buf, *out_buf;
+ union PRNetAddr netaddr;
+ PRInt32 bytes, i, j;
+
+
+ DPRINTF(("TCP client started\n"));
+ bytes = cp->datalen;
+ out_buf = PR_NEW(buffer);
+ if (out_buf == NULL) {
+ fprintf(stderr,"%s: failed to alloc buffer struct\n", program_name);
+ failed_already=1;
+ return;
+ }
+ in_buf = PR_NEW(buffer);
+ if (in_buf == NULL) {
+ fprintf(stderr,"%s: failed to alloc buffer struct\n", program_name);
+ failed_already=1;
+ return;
+ }
+ netaddr.inet.family = cp->server_addr.inet.family;
+ netaddr.inet.port = cp->server_addr.inet.port;
+ netaddr.inet.ip = cp->server_addr.inet.ip;
+
+ for (i = 0; i < num_tcp_connections_per_client; i++) {
+ if ((sockfd = PR_OpenTCPSocket(PR_AF_INET)) == NULL) {
+ fprintf(stderr,"%s: PR_OpenTCPSocket failed\n", program_name);
+ failed_already=1;
+ return;
+ }
+
+ DPRINTF(("TCP client connecting to server:%d\n", server_port));
+ if (PR_Connect(sockfd, &netaddr,PR_INTERVAL_NO_TIMEOUT) < 0) {
+ fprintf(stderr, "PR_Connect failed: (%ld, %ld)\n",
+ PR_GetError(), PR_GetOSError());
+ failed_already=1;
+ return;
+ }
+ for (j = 0; j < num_tcp_mesgs_per_connection; j++) {
+ /*
+ * fill in random data
+ */
+ memset(out_buf->data, ((PRInt32) (&netaddr)) + i + j, bytes);
+ /*
+ * write to server
+ */
+ if (writen(sockfd, out_buf->data, bytes) < bytes) {
+ fprintf(stderr,"%s: ERROR - TCP_Client:writen\n", program_name);
+ failed_already=1;
+ return;
+ }
+ /*
+ DPRINTF(("TCP Client [0x%lx]: out_buf = 0x%lx out_buf[0] = 0x%lx\n",
+ PR_GetCurrentThread(), out_buf, (*((int *) out_buf->data))));
+ */
+ if (readn(sockfd, in_buf->data, bytes) < bytes) {
+ fprintf(stderr,"%s: ERROR - TCP_Client:readn\n", program_name);
+ failed_already=1;
+ return;
+ }
+ /*
+ * verify the data read
+ */
+ if (memcmp(in_buf->data, out_buf->data, bytes) != 0) {
+ fprintf(stderr,"%s: ERROR - data corruption\n", program_name);
+ failed_already=1;
+ return;
+ }
+ }
+ /*
+ * shutdown reads and writes
+ */
+ if (PR_Shutdown(sockfd, PR_SHUTDOWN_BOTH) < 0) {
+ fprintf(stderr,"%s: ERROR - PR_Shutdown\n", program_name);
+ failed_already=1;
+ }
+ PR_Close(sockfd);
+ }
+
+ PR_DELETE(out_buf);
+ PR_DELETE(in_buf);
+
+ /*
+ * Decrement exit_counter and notify parent thread
+ */
+
+ PR_EnterMonitor(cp->exit_mon);
+ --(*cp->exit_counter);
+ PR_Notify(cp->exit_mon);
+ PR_ExitMonitor(cp->exit_mon);
+ DPRINTF(("TCP_Client exiting\n"));
+}
+
+/*
+ * TCP_Socket_Client_Server_Test - concurrent server test
+ *
+ * Each client connects to the server and sends a chunk of data
+ * For each connection, server reads the data
+ * from the client and sends it back to the client, unmodified.
+ * Each client checks that data received from server is same as the
+ * data it sent to the server.
+ *
+ */
+
+static PRInt32
+TCP_Socket_Client_Server_Test(void)
+{
+ int i;
+ Client_Param *cparamp;
+ PRMonitor *mon2;
+ PRInt32 datalen;
+ PRInt32 connections = 0;
+ PRThread *thr;
+
+ datalen = tcp_mesg_size;
+ connections = 0;
+
+ mon2 = PR_NewMonitor();
+ if (mon2 == NULL) {
+ fprintf(stderr,"%s: PR_NewMonitor failed\n", program_name);
+ failed_already=1;
+ return -1;
+ }
+
+ /*
+ * Start client jobs
+ */
+ cparamp = PR_NEW(Client_Param);
+ if (cparamp == NULL) {
+ fprintf(stderr,"%s: PR_NEW failed\n", program_name);
+ failed_already=1;
+ return -1;
+ }
+ cparamp->server_addr.inet.family = PR_AF_INET;
+ cparamp->server_addr.inet.port = PR_htons(server_port);
+ cparamp->server_addr.inet.ip = PR_htonl(PR_INADDR_LOOPBACK);
+ cparamp->exit_mon = mon2;
+ cparamp->exit_counter = &connections;
+ cparamp->datalen = datalen;
+ for (i = 0; i < num_tcp_clients; i++) {
+ thr = PR_CreateThread(PR_USER_THREAD, TCP_Client, (void *)cparamp,
+ PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD, 0);
+ if (NULL == thr) {
+ fprintf(stderr,"%s: PR_CreateThread failed\n", program_name);
+ failed_already=1;
+ return -1;
+ }
+ PR_EnterMonitor(mon2);
+ connections++;
+ PR_ExitMonitor(mon2);
+ DPRINTF(("Created TCP client = 0x%lx\n", thr));
+ }
+ /* Wait for client jobs to exit */
+ PR_EnterMonitor(mon2);
+ while (0 != connections) {
+ PR_Wait(mon2, PR_INTERVAL_NO_TIMEOUT);
+ DPRINTF(("Client job count = %d\n", connections));
+ }
+ PR_ExitMonitor(mon2);
+ printf("%30s","TCP_Socket_Client_Server_Test:");
+ printf("%2ld Server %2ld Clients %2ld connections_per_client\n",1l,
+ num_tcp_clients, num_tcp_connections_per_client);
+ printf("%30s %2ld messages_per_connection %4ld bytes_per_message\n",":",
+ num_tcp_mesgs_per_connection, tcp_mesg_size);
+
+ PR_DELETE(cparamp);
+ return 0;
+}
+
+/************************************************************************/
+
+int main(int argc, char **argv)
+{
+ /*
+ * -d debug mode
+ */
+ PLOptStatus os;
+ PLOptState *opt;
+ program_name = argv[0];
+
+ opt = PL_CreateOptState(argc, argv, "dp:");
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 'd': /* debug mode */
+ _debug_on = 1;
+ break;
+ case 'p':
+ server_port = atoi(opt->value);
+ break;
+ default:
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
+ PR_STDIO_INIT();
+
+ PR_SetConcurrency(4);
+
+ TCP_Socket_Client_Server_Test();
+
+ PR_Cleanup();
+ if (failed_already) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+}
diff --git a/nsprpub/pr/tests/thrpool_server.c b/nsprpub/pr/tests/thrpool_server.c
new file mode 100644
index 0000000000..ecae117a8e
--- /dev/null
+++ b/nsprpub/pr/tests/thrpool_server.c
@@ -0,0 +1,579 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/***********************************************************************
+**
+** Name: thrpool.c
+**
+** Description: Test threadpool functionality.
+**
+** Modification History:
+*/
+#include "primpl.h"
+
+#include "plgetopt.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#ifdef XP_UNIX
+#include <sys/mman.h>
+#endif
+#if defined(_PR_PTHREADS)
+#include <pthread.h>
+#endif
+
+/* for getcwd */
+#if defined(XP_UNIX) || defined (XP_OS2)
+#include <unistd.h>
+#elif defined(XP_PC)
+#include <direct.h>
+#endif
+
+#ifdef WIN32
+#include <process.h>
+#endif
+
+static int _debug_on = 0;
+static char *program_name = NULL;
+static void serve_client_write(void *arg);
+
+#include "obsolete/prsem.h"
+
+#ifdef XP_PC
+#define mode_t int
+#endif
+
+#define DPRINTF(arg) if (_debug_on) printf arg
+
+
+#define BUF_DATA_SIZE (2 * 1024)
+#define TCP_MESG_SIZE 1024
+#define NUM_TCP_CLIENTS 10 /* for a listen queue depth of 5 */
+
+
+#define NUM_TCP_CONNECTIONS_PER_CLIENT 10
+#define NUM_TCP_MESGS_PER_CONNECTION 10
+#define TCP_SERVER_PORT 10000
+#define SERVER_MAX_BIND_COUNT 100
+
+#ifdef WINCE
+char *getcwd(char *buf, size_t size)
+{
+ wchar_t wpath[MAX_PATH];
+ _wgetcwd(wpath, MAX_PATH);
+ WideCharToMultiByte(CP_ACP, 0, wpath, -1, buf, size, 0, 0);
+}
+
+#define perror(s)
+#endif
+
+static PRInt32 num_tcp_clients = NUM_TCP_CLIENTS;
+static PRInt32 num_tcp_connections_per_client = NUM_TCP_CONNECTIONS_PER_CLIENT;
+static PRInt32 tcp_mesg_size = TCP_MESG_SIZE;
+static PRInt32 num_tcp_mesgs_per_connection = NUM_TCP_MESGS_PER_CONNECTION;
+static void TCP_Server_Accept(void *arg);
+
+
+int failed_already=0;
+typedef struct buffer {
+ char data[BUF_DATA_SIZE];
+} buffer;
+
+
+typedef struct Server_Param {
+ PRJobIoDesc iod; /* socket to read from/write to */
+ PRInt32 datalen; /* bytes of data transfered in each read/write */
+ PRNetAddr netaddr;
+ PRMonitor *exit_mon; /* monitor to signal on exit */
+ PRInt32 *job_counterp; /* counter to decrement, before exit */
+ PRInt32 conn_counter; /* counter to decrement, before exit */
+ PRThreadPool *tp;
+} Server_Param;
+
+typedef struct Serve_Client_Param {
+ PRJobIoDesc iod; /* socket to read from/write to */
+ PRInt32 datalen; /* bytes of data transfered in each read/write */
+ PRMonitor *exit_mon; /* monitor to signal on exit */
+ PRInt32 *job_counterp; /* counter to decrement, before exit */
+ PRThreadPool *tp;
+} Serve_Client_Param;
+
+typedef struct Session {
+ PRJobIoDesc iod; /* socket to read from/write to */
+ buffer *in_buf;
+ PRInt32 bytes;
+ PRInt32 msg_num;
+ PRInt32 bytes_read;
+ PRMonitor *exit_mon; /* monitor to signal on exit */
+ PRInt32 *job_counterp; /* counter to decrement, before exit */
+ PRThreadPool *tp;
+} Session;
+
+static void
+serve_client_read(void *arg)
+{
+ Session *sp = (Session *) arg;
+ int rem;
+ int bytes;
+ int offset;
+ PRFileDesc *sockfd;
+ char *buf;
+ PRJob *jobp;
+
+ PRIntervalTime timeout = PR_INTERVAL_NO_TIMEOUT;
+
+ sockfd = sp->iod.socket;
+ buf = sp->in_buf->data;
+
+ PR_ASSERT(sp->msg_num < num_tcp_mesgs_per_connection);
+ PR_ASSERT(sp->bytes_read < sp->bytes);
+
+ offset = sp->bytes_read;
+ rem = sp->bytes - offset;
+ bytes = PR_Recv(sockfd, buf + offset, rem, 0, timeout);
+ if (bytes < 0) {
+ return;
+ }
+ sp->bytes_read += bytes;
+ sp->iod.timeout = PR_SecondsToInterval(60);
+ if (sp->bytes_read < sp->bytes) {
+ jobp = PR_QueueJob_Read(sp->tp, &sp->iod, serve_client_read, sp,
+ PR_FALSE);
+ PR_ASSERT(NULL != jobp);
+ return;
+ }
+ PR_ASSERT(sp->bytes_read == sp->bytes);
+ DPRINTF(("serve_client: read complete, msg(%d) \n", sp->msg_num));
+
+ sp->iod.timeout = PR_SecondsToInterval(60);
+ jobp = PR_QueueJob_Write(sp->tp, &sp->iod, serve_client_write, sp,
+ PR_FALSE);
+ PR_ASSERT(NULL != jobp);
+
+ return;
+}
+
+static void
+serve_client_write(void *arg)
+{
+ Session *sp = (Session *) arg;
+ int bytes;
+ PRFileDesc *sockfd;
+ char *buf;
+ PRJob *jobp;
+
+ sockfd = sp->iod.socket;
+ buf = sp->in_buf->data;
+
+ PR_ASSERT(sp->msg_num < num_tcp_mesgs_per_connection);
+
+ bytes = PR_Send(sockfd, buf, sp->bytes, 0, PR_INTERVAL_NO_TIMEOUT);
+ PR_ASSERT(bytes == sp->bytes);
+
+ if (bytes < 0) {
+ return;
+ }
+ DPRINTF(("serve_client: write complete, msg(%d) \n", sp->msg_num));
+ sp->msg_num++;
+ if (sp->msg_num < num_tcp_mesgs_per_connection) {
+ sp->bytes_read = 0;
+ sp->iod.timeout = PR_SecondsToInterval(60);
+ jobp = PR_QueueJob_Read(sp->tp, &sp->iod, serve_client_read, sp,
+ PR_FALSE);
+ PR_ASSERT(NULL != jobp);
+ return;
+ }
+
+ DPRINTF(("serve_client: read/write complete, msg(%d) \n", sp->msg_num));
+ if (PR_Shutdown(sockfd, PR_SHUTDOWN_BOTH) < 0) {
+ fprintf(stderr,"%s: ERROR - PR_Shutdown\n", program_name);
+ }
+
+ PR_Close(sockfd);
+ PR_EnterMonitor(sp->exit_mon);
+ --(*sp->job_counterp);
+ PR_Notify(sp->exit_mon);
+ PR_ExitMonitor(sp->exit_mon);
+
+ PR_DELETE(sp->in_buf);
+ PR_DELETE(sp);
+
+ return;
+}
+
+/*
+ * Serve_Client
+ * Thread, started by the server, for serving a client connection.
+ * Reads data from socket and writes it back, unmodified, and
+ * closes the socket
+ */
+static void PR_CALLBACK
+Serve_Client(void *arg)
+{
+ Serve_Client_Param *scp = (Serve_Client_Param *) arg;
+ buffer *in_buf;
+ Session *sp;
+ PRJob *jobp;
+
+ sp = PR_NEW(Session);
+ sp->iod = scp->iod;
+
+ in_buf = PR_NEW(buffer);
+ if (in_buf == NULL) {
+ fprintf(stderr,"%s: failed to alloc buffer struct\n",program_name);
+ failed_already=1;
+ return;
+ }
+
+ sp->in_buf = in_buf;
+ sp->bytes = scp->datalen;
+ sp->msg_num = 0;
+ sp->bytes_read = 0;
+ sp->tp = scp->tp;
+ sp->exit_mon = scp->exit_mon;
+ sp->job_counterp = scp->job_counterp;
+
+ sp->iod.timeout = PR_SecondsToInterval(60);
+ jobp = PR_QueueJob_Read(sp->tp, &sp->iod, serve_client_read, sp,
+ PR_FALSE);
+ PR_ASSERT(NULL != jobp);
+ PR_DELETE(scp);
+}
+
+static void
+print_stats(void *arg)
+{
+ Server_Param *sp = (Server_Param *) arg;
+ PRThreadPool *tp = sp->tp;
+ PRInt32 counter;
+ PRJob *jobp;
+
+ PR_EnterMonitor(sp->exit_mon);
+ counter = (*sp->job_counterp);
+ PR_ExitMonitor(sp->exit_mon);
+
+ printf("PRINT_STATS: #client connections = %d\n",counter);
+
+
+ jobp = PR_QueueJob_Timer(tp, PR_MillisecondsToInterval(500),
+ print_stats, sp, PR_FALSE);
+
+ PR_ASSERT(NULL != jobp);
+}
+
+static int job_counter = 0;
+/*
+ * TCP Server
+ * Server binds an address to a socket, starts a client process and
+ * listens for incoming connections.
+ * Each client connects to the server and sends a chunk of data
+ * Starts a Serve_Client job for each incoming connection, to read
+ * the data from the client and send it back to the client, unmodified.
+ * Each client checks that data received from server is same as the
+ * data it sent to the server.
+ * Finally, the threadpool is shutdown
+ */
+static void PR_CALLBACK
+TCP_Server(void *arg)
+{
+ PRThreadPool *tp = (PRThreadPool *) arg;
+ Server_Param *sp;
+ PRFileDesc *sockfd;
+ PRNetAddr netaddr;
+ PRMonitor *sc_mon;
+ PRJob *jobp;
+ int i;
+ PRStatus rval;
+
+ /*
+ * Create a tcp socket
+ */
+ if ((sockfd = PR_NewTCPSocket()) == NULL) {
+ fprintf(stderr,"%s: PR_NewTCPSocket failed\n", program_name);
+ return;
+ }
+ memset(&netaddr, 0, sizeof(netaddr));
+ netaddr.inet.family = PR_AF_INET;
+ netaddr.inet.port = PR_htons(TCP_SERVER_PORT);
+ netaddr.inet.ip = PR_htonl(PR_INADDR_ANY);
+ /*
+ * try a few times to bind server's address, if addresses are in
+ * use
+ */
+ i = 0;
+ while (PR_Bind(sockfd, &netaddr) < 0) {
+ if (PR_GetError() == PR_ADDRESS_IN_USE_ERROR) {
+ netaddr.inet.port += 2;
+ if (i++ < SERVER_MAX_BIND_COUNT) {
+ continue;
+ }
+ }
+ fprintf(stderr,"%s: ERROR - PR_Bind failed\n", program_name);
+ perror("PR_Bind");
+ failed_already=1;
+ return;
+ }
+
+ if (PR_Listen(sockfd, 32) < 0) {
+ fprintf(stderr,"%s: ERROR - PR_Listen failed\n", program_name);
+ failed_already=1;
+ return;
+ }
+
+ if (PR_GetSockName(sockfd, &netaddr) < 0) {
+ fprintf(stderr,"%s: ERROR - PR_GetSockName failed\n", program_name);
+ failed_already=1;
+ return;
+ }
+
+ DPRINTF((
+ "TCP_Server: PR_BIND netaddr.inet.ip = 0x%lx, netaddr.inet.port = %d\n",
+ netaddr.inet.ip, netaddr.inet.port));
+
+ sp = PR_NEW(Server_Param);
+ if (sp == NULL) {
+ fprintf(stderr,"%s: PR_NEW failed\n", program_name);
+ failed_already=1;
+ return;
+ }
+ sp->iod.socket = sockfd;
+ sp->iod.timeout = PR_SecondsToInterval(60);
+ sp->datalen = tcp_mesg_size;
+ sp->exit_mon = sc_mon;
+ sp->job_counterp = &job_counter;
+ sp->conn_counter = 0;
+ sp->tp = tp;
+ sp->netaddr = netaddr;
+
+ /* create and cancel an io job */
+ jobp = PR_QueueJob_Accept(tp, &sp->iod, TCP_Server_Accept, sp,
+ PR_FALSE);
+ PR_ASSERT(NULL != jobp);
+ rval = PR_CancelJob(jobp);
+ PR_ASSERT(PR_SUCCESS == rval);
+
+ /*
+ * create the client process
+ */
+ {
+#define MAX_ARGS 4
+ char *argv[MAX_ARGS + 1];
+ int index = 0;
+ char port[32];
+ char path[1024 + sizeof("/thrpool_client")];
+
+ getcwd(path, sizeof(path));
+
+ (void)strcat(path, "/thrpool_client");
+#ifdef XP_PC
+ (void)strcat(path, ".exe");
+#endif
+ argv[index++] = path;
+ sprintf(port,"%d",PR_ntohs(netaddr.inet.port));
+ if (_debug_on)
+ {
+ argv[index++] = "-d";
+ argv[index++] = "-p";
+ argv[index++] = port;
+ argv[index++] = NULL;
+ } else {
+ argv[index++] = "-p";
+ argv[index++] = port;
+ argv[index++] = NULL;
+ }
+ PR_ASSERT(MAX_ARGS >= (index - 1));
+
+ DPRINTF(("creating client process %s ...\n", path));
+ if (PR_FAILURE == PR_CreateProcessDetached(path, argv, NULL, NULL)) {
+ fprintf(stderr,
+ "thrpool_server: ERROR - PR_CreateProcessDetached failed\n");
+ failed_already=1;
+ return;
+ }
+ }
+
+ sc_mon = PR_NewMonitor();
+ if (sc_mon == NULL) {
+ fprintf(stderr,"%s: PR_NewMonitor failed\n", program_name);
+ failed_already=1;
+ return;
+ }
+
+ sp->iod.socket = sockfd;
+ sp->iod.timeout = PR_SecondsToInterval(60);
+ sp->datalen = tcp_mesg_size;
+ sp->exit_mon = sc_mon;
+ sp->job_counterp = &job_counter;
+ sp->conn_counter = 0;
+ sp->tp = tp;
+ sp->netaddr = netaddr;
+
+ /* create and cancel a timer job */
+ jobp = PR_QueueJob_Timer(tp, PR_MillisecondsToInterval(5000),
+ print_stats, sp, PR_FALSE);
+ PR_ASSERT(NULL != jobp);
+ rval = PR_CancelJob(jobp);
+ PR_ASSERT(PR_SUCCESS == rval);
+
+ DPRINTF(("TCP_Server: Accepting connections \n"));
+
+ jobp = PR_QueueJob_Accept(tp, &sp->iod, TCP_Server_Accept, sp,
+ PR_FALSE);
+ PR_ASSERT(NULL != jobp);
+ return;
+}
+
+static void
+TCP_Server_Accept(void *arg)
+{
+ Server_Param *sp = (Server_Param *) arg;
+ PRThreadPool *tp = sp->tp;
+ Serve_Client_Param *scp;
+ PRFileDesc *newsockfd;
+ PRJob *jobp;
+
+ if ((newsockfd = PR_Accept(sp->iod.socket, &sp->netaddr,
+ PR_INTERVAL_NO_TIMEOUT)) == NULL) {
+ fprintf(stderr,"%s: ERROR - PR_Accept failed\n", program_name);
+ failed_already=1;
+ goto exit;
+ }
+ scp = PR_NEW(Serve_Client_Param);
+ if (scp == NULL) {
+ fprintf(stderr,"%s: PR_NEW failed\n", program_name);
+ failed_already=1;
+ goto exit;
+ }
+
+ /*
+ * Start a Serve_Client job for each incoming connection
+ */
+ scp->iod.socket = newsockfd;
+ scp->iod.timeout = PR_SecondsToInterval(60);
+ scp->datalen = tcp_mesg_size;
+ scp->exit_mon = sp->exit_mon;
+ scp->job_counterp = sp->job_counterp;
+ scp->tp = sp->tp;
+
+ PR_EnterMonitor(sp->exit_mon);
+ (*sp->job_counterp)++;
+ PR_ExitMonitor(sp->exit_mon);
+ jobp = PR_QueueJob(tp, Serve_Client, scp,
+ PR_FALSE);
+
+ PR_ASSERT(NULL != jobp);
+ DPRINTF(("TCP_Server: Created Serve_Client = 0x%lx\n", jobp));
+
+ /*
+ * single-threaded update; no lock needed
+ */
+ sp->conn_counter++;
+ if (sp->conn_counter <
+ (num_tcp_clients * num_tcp_connections_per_client)) {
+ jobp = PR_QueueJob_Accept(tp, &sp->iod, TCP_Server_Accept, sp,
+ PR_FALSE);
+ PR_ASSERT(NULL != jobp);
+ return;
+ }
+ jobp = PR_QueueJob_Timer(tp, PR_MillisecondsToInterval(500),
+ print_stats, sp, PR_FALSE);
+
+ PR_ASSERT(NULL != jobp);
+ DPRINTF(("TCP_Server: Created print_stats timer job = 0x%lx\n", jobp));
+
+exit:
+ PR_EnterMonitor(sp->exit_mon);
+ /* Wait for server jobs to finish */
+ while (0 != *sp->job_counterp) {
+ PR_Wait(sp->exit_mon, PR_INTERVAL_NO_TIMEOUT);
+ DPRINTF(("TCP_Server: conn_counter = %d\n",
+ *sp->job_counterp));
+ }
+
+ PR_ExitMonitor(sp->exit_mon);
+ if (sp->iod.socket) {
+ PR_Close(sp->iod.socket);
+ }
+ PR_DestroyMonitor(sp->exit_mon);
+ printf("%30s","TCP_Socket_Client_Server_Test:");
+ printf("%2ld Server %2ld Clients %2ld connections_per_client\n",1l,
+ num_tcp_clients, num_tcp_connections_per_client);
+ printf("%30s %2ld messages_per_connection %4ld bytes_per_message\n",":",
+ num_tcp_mesgs_per_connection, tcp_mesg_size);
+
+ DPRINTF(("%s: calling PR_ShutdownThreadPool\n", program_name));
+ PR_ShutdownThreadPool(sp->tp);
+ PR_DELETE(sp);
+}
+
+/************************************************************************/
+
+#define DEFAULT_INITIAL_THREADS 4
+#define DEFAULT_MAX_THREADS 100
+#define DEFAULT_STACKSIZE (512 * 1024)
+
+int main(int argc, char **argv)
+{
+ PRInt32 initial_threads = DEFAULT_INITIAL_THREADS;
+ PRInt32 max_threads = DEFAULT_MAX_THREADS;
+ PRInt32 stacksize = DEFAULT_STACKSIZE;
+ PRThreadPool *tp = NULL;
+ PRStatus rv;
+ PRJob *jobp;
+
+ /*
+ * -d debug mode
+ */
+ PLOptStatus os;
+ PLOptState *opt;
+
+ program_name = argv[0];
+ opt = PL_CreateOptState(argc, argv, "d");
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 'd': /* debug mode */
+ _debug_on = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
+ PR_STDIO_INIT();
+
+ PR_SetConcurrency(4);
+
+ tp = PR_CreateThreadPool(initial_threads, max_threads, stacksize);
+ if (NULL == tp) {
+ printf("PR_CreateThreadPool failed\n");
+ failed_already=1;
+ goto done;
+ }
+ jobp = PR_QueueJob(tp, TCP_Server, tp, PR_TRUE);
+ rv = PR_JoinJob(jobp);
+ PR_ASSERT(PR_SUCCESS == rv);
+
+ DPRINTF(("%s: calling PR_JoinThreadPool\n", program_name));
+ rv = PR_JoinThreadPool(tp);
+ PR_ASSERT(PR_SUCCESS == rv);
+ DPRINTF(("%s: returning from PR_JoinThreadPool\n", program_name));
+
+done:
+ PR_Cleanup();
+ if (failed_already) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+}
diff --git a/nsprpub/pr/tests/thruput.c b/nsprpub/pr/tests/thruput.c
new file mode 100644
index 0000000000..156bbde9a3
--- /dev/null
+++ b/nsprpub/pr/tests/thruput.c
@@ -0,0 +1,414 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+** File: thruput.c
+** Description: Test server's throughput capability comparing various
+** implmentation strategies.
+**
+** Note: Requires a server machine and an aribitrary number of
+** clients to bang on it. Trust the numbers on the server
+** more than those being displayed by the various clients.
+*/
+
+#include "prerror.h"
+#include "prinrval.h"
+#include "prinit.h"
+#include "prio.h"
+#include "prlock.h"
+#include "prmem.h"
+#include "prnetdb.h"
+#include "prprf.h"
+#include "prthread.h"
+#include "pprio.h"
+#include "plerror.h"
+#include "plgetopt.h"
+
+#define ADDR_BUFFER 100
+
+#ifdef DEBUG
+#define PORT_INC_DO +100
+#else
+#define PORT_INC_DO
+#endif
+#ifdef IS_64
+#define PORT_INC_3264 +200
+#else
+#define PORT_INC_3264
+#endif
+
+#define PORT_NUMBER 51877 PORT_INC_DO PORT_INC_3264
+
+#define SAMPLING_INTERVAL 10
+#define BUFFER_SIZE (32 * 1024)
+
+static PRInt32 domain = PR_AF_INET;
+static PRInt32 protocol = 6; /* TCP */
+static PRFileDesc *err = NULL;
+static PRIntn concurrency = 1;
+static PRInt32 xport_buffer = -1;
+static PRUint32 initial_streams = 1;
+static PRInt32 buffer_size = BUFFER_SIZE;
+static PRThreadScope thread_scope = PR_LOCAL_THREAD;
+
+typedef struct Shared
+{
+ PRLock *ml;
+ PRUint32 sampled;
+ PRUint32 threads;
+ PRIntervalTime timein;
+ PRNetAddr server_address;
+} Shared;
+
+static Shared *shared = NULL;
+
+static PRStatus PrintAddress(const PRNetAddr* address)
+{
+ char buffer[ADDR_BUFFER];
+ PRStatus rv = PR_NetAddrToString(address, buffer, sizeof(buffer));
+ if (PR_SUCCESS == rv) {
+ PR_fprintf(err, "%s:%u\n", buffer, PR_ntohs(address->inet.port));
+ }
+ else {
+ PL_FPrintError(err, "PR_NetAddrToString");
+ }
+ return rv;
+} /* PrintAddress */
+
+
+static void PR_CALLBACK Clientel(void *arg)
+{
+ PRStatus rv;
+ PRFileDesc *xport;
+ PRInt32 bytes, sampled;
+ PRIntervalTime now, interval;
+ PRBool do_display = PR_FALSE;
+ Shared *shared = (Shared*)arg;
+ char *buffer = (char*)PR_Malloc(buffer_size);
+ PRNetAddr *server_address = &shared->server_address;
+ PRIntervalTime connect_timeout = PR_SecondsToInterval(5);
+ PRIntervalTime sampling_interval = PR_SecondsToInterval(SAMPLING_INTERVAL);
+
+ PR_fprintf(err, "Client connecting to ");
+ (void)PrintAddress(server_address);
+
+ do
+ {
+ xport = PR_Socket(domain, PR_SOCK_STREAM, protocol);
+ if (NULL == xport)
+ {
+ PL_FPrintError(err, "PR_Socket");
+ return;
+ }
+
+ if (xport_buffer != -1)
+ {
+ PRSocketOptionData data;
+ data.option = PR_SockOpt_RecvBufferSize;
+ data.value.recv_buffer_size = (PRSize)xport_buffer;
+ rv = PR_SetSocketOption(xport, &data);
+ if (PR_FAILURE == rv) {
+ PL_FPrintError(err, "PR_SetSocketOption - ignored");
+ }
+ data.option = PR_SockOpt_SendBufferSize;
+ data.value.send_buffer_size = (PRSize)xport_buffer;
+ rv = PR_SetSocketOption(xport, &data);
+ if (PR_FAILURE == rv) {
+ PL_FPrintError(err, "PR_SetSocketOption - ignored");
+ }
+ }
+
+ rv = PR_Connect(xport, server_address, connect_timeout);
+ if (PR_FAILURE == rv)
+ {
+ PL_FPrintError(err, "PR_Connect");
+ if (PR_IO_TIMEOUT_ERROR != PR_GetError()) {
+ PR_Sleep(connect_timeout);
+ }
+ PR_Close(xport); /* delete it and start over */
+ }
+ } while (PR_FAILURE == rv);
+
+ do
+ {
+ bytes = PR_Recv(
+ xport, buffer, buffer_size, 0, PR_INTERVAL_NO_TIMEOUT);
+ PR_Lock(shared->ml);
+ now = PR_IntervalNow();
+ shared->sampled += bytes;
+ interval = now - shared->timein;
+ if (interval > sampling_interval)
+ {
+ sampled = shared->sampled;
+ shared->timein = now;
+ shared->sampled = 0;
+ do_display = PR_TRUE;
+ }
+ PR_Unlock(shared->ml);
+
+ if (do_display)
+ {
+ PRUint32 rate = sampled / PR_IntervalToMilliseconds(interval);
+ PR_fprintf(err, "%u streams @ %u Kbytes/sec\n", shared->threads, rate);
+ do_display = PR_FALSE;
+ }
+
+ } while (bytes > 0);
+} /* Clientel */
+
+static void Client(const char *server_name)
+{
+ PRStatus rv;
+ PRHostEnt host;
+ char buffer[PR_NETDB_BUF_SIZE];
+ PRIntervalTime dally = PR_SecondsToInterval(60);
+ PR_fprintf(err, "Translating the name %s\n", server_name);
+ rv = PR_GetHostByName(server_name, buffer, sizeof(buffer), &host);
+ if (PR_FAILURE == rv) {
+ PL_FPrintError(err, "PR_GetHostByName");
+ }
+ else
+ {
+ if (PR_EnumerateHostEnt(
+ 0, &host, PORT_NUMBER, &shared->server_address) < 0) {
+ PL_FPrintError(err, "PR_EnumerateHostEnt");
+ }
+ else
+ {
+ do
+ {
+ shared->threads += 1;
+ (void)PR_CreateThread(
+ PR_USER_THREAD, Clientel, shared,
+ PR_PRIORITY_NORMAL, thread_scope,
+ PR_UNJOINABLE_THREAD, 8 * 1024);
+ if (shared->threads == initial_streams)
+ {
+ PR_Sleep(dally);
+ initial_streams += 1;
+ }
+ } while (PR_TRUE);
+ }
+ }
+}
+
+static void PR_CALLBACK Servette(void *arg)
+{
+ PRInt32 bytes, sampled;
+ PRIntervalTime now, interval;
+ PRBool do_display = PR_FALSE;
+ PRFileDesc *client = (PRFileDesc*)arg;
+ char *buffer = (char*)PR_Malloc(buffer_size);
+ PRIntervalTime sampling_interval = PR_SecondsToInterval(SAMPLING_INTERVAL);
+
+ if (xport_buffer != -1)
+ {
+ PRStatus rv;
+ PRSocketOptionData data;
+ data.option = PR_SockOpt_RecvBufferSize;
+ data.value.recv_buffer_size = (PRSize)xport_buffer;
+ rv = PR_SetSocketOption(client, &data);
+ if (PR_FAILURE == rv) {
+ PL_FPrintError(err, "PR_SetSocketOption - ignored");
+ }
+ data.option = PR_SockOpt_SendBufferSize;
+ data.value.send_buffer_size = (PRSize)xport_buffer;
+ rv = PR_SetSocketOption(client, &data);
+ if (PR_FAILURE == rv) {
+ PL_FPrintError(err, "PR_SetSocketOption - ignored");
+ }
+ }
+
+ do
+ {
+ bytes = PR_Send(
+ client, buffer, buffer_size, 0, PR_INTERVAL_NO_TIMEOUT);
+
+ PR_Lock(shared->ml);
+ now = PR_IntervalNow();
+ shared->sampled += bytes;
+ interval = now - shared->timein;
+ if (interval > sampling_interval)
+ {
+ sampled = shared->sampled;
+ shared->timein = now;
+ shared->sampled = 0;
+ do_display = PR_TRUE;
+ }
+ PR_Unlock(shared->ml);
+
+ if (do_display)
+ {
+ PRUint32 rate = sampled / PR_IntervalToMilliseconds(interval);
+ PR_fprintf(err, "%u streams @ %u Kbytes/sec\n", shared->threads, rate);
+ do_display = PR_FALSE;
+ }
+ } while (bytes > 0);
+} /* Servette */
+
+static void Server(void)
+{
+ PRStatus rv;
+ PRNetAddr server_address, client_address;
+ PRFileDesc *xport = PR_Socket(domain, PR_SOCK_STREAM, protocol);
+
+ if (NULL == xport)
+ {
+ PL_FPrintError(err, "PR_Socket");
+ return;
+ }
+
+ rv = PR_InitializeNetAddr(PR_IpAddrAny, PORT_NUMBER, &server_address);
+ if (PR_FAILURE == rv) {
+ PL_FPrintError(err, "PR_InitializeNetAddr");
+ }
+ else
+ {
+ rv = PR_Bind(xport, &server_address);
+ if (PR_FAILURE == rv) {
+ PL_FPrintError(err, "PR_Bind");
+ }
+ else
+ {
+ PRFileDesc *client;
+ rv = PR_Listen(xport, 10);
+ PR_fprintf(err, "Server listening on ");
+ (void)PrintAddress(&server_address);
+ do
+ {
+ client = PR_Accept(
+ xport, &client_address, PR_INTERVAL_NO_TIMEOUT);
+ if (NULL == client) {
+ PL_FPrintError(err, "PR_Accept");
+ }
+ else
+ {
+ PR_fprintf(err, "Server accepting from ");
+ (void)PrintAddress(&client_address);
+ shared->threads += 1;
+ (void)PR_CreateThread(
+ PR_USER_THREAD, Servette, client,
+ PR_PRIORITY_NORMAL, thread_scope,
+ PR_UNJOINABLE_THREAD, 8 * 1024);
+ }
+ } while (PR_TRUE);
+
+ }
+ }
+} /* Server */
+
+static void Help(void)
+{
+ PR_fprintf(err, "Usage: [-h] [<server>]\n");
+ PR_fprintf(err, "\t-s <n> Initial # of connections (default: 1)\n");
+ PR_fprintf(err, "\t-C <n> Set 'concurrency' (default: 1)\n");
+ PR_fprintf(err, "\t-b <nK> Client buffer size (default: 32k)\n");
+ PR_fprintf(err, "\t-B <nK> Transport recv/send buffer size (default: sys)\n");
+ PR_fprintf(err, "\t-G Use GLOBAL threads (default: LOCAL)\n");
+ PR_fprintf(err, "\t-X Use XTP transport (default: TCP)\n");
+ PR_fprintf(err, "\t-6 Use IPv6 (default: IPv4)\n");
+ PR_fprintf(err, "\t-h This message and nothing else\n");
+ PR_fprintf(err, "\t<server> DNS name of server\n");
+ PR_fprintf(err, "\t\tIf <server> is not specified, this host will be\n");
+ PR_fprintf(err, "\t\tthe server and not act as a client.\n");
+} /* Help */
+
+int main(int argc, char **argv)
+{
+ PLOptStatus os;
+ const char *server_name = NULL;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "hGX6C:b:s:B:");
+
+ err = PR_GetSpecialFD(PR_StandardError);
+
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 0: /* Name of server */
+ server_name = opt->value;
+ break;
+ case 'G': /* Globular threads */
+ thread_scope = PR_GLOBAL_THREAD;
+ break;
+ case 'X': /* Use XTP as the transport */
+ protocol = 36;
+ break;
+ case '6': /* Use IPv6 */
+ domain = PR_AF_INET6;
+ break;
+ case 's': /* initial_streams */
+ initial_streams = atoi(opt->value);
+ break;
+ case 'C': /* concurrency */
+ concurrency = atoi(opt->value);
+ break;
+ case 'b': /* buffer size */
+ buffer_size = 1024 * atoi(opt->value);
+ break;
+ case 'B': /* buffer size */
+ xport_buffer = 1024 * atoi(opt->value);
+ break;
+ case 'h': /* user wants some guidance */
+ default:
+ Help(); /* so give him an earful */
+ return 2; /* but not a lot else */
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ shared = PR_NEWZAP(Shared);
+ shared->ml = PR_NewLock();
+
+ PR_fprintf(err,
+ "This machine is %s\n",
+ (NULL == server_name) ? "the SERVER" : "a CLIENT");
+
+ PR_fprintf(err,
+ "Transport being used is %s\n",
+ (6 == protocol) ? "TCP" : "XTP");
+
+ if (PR_GLOBAL_THREAD == thread_scope)
+ {
+ if (1 != concurrency)
+ {
+ PR_fprintf(err, " **Concurrency > 1 and GLOBAL threads!?!?\n");
+ PR_fprintf(err, " **Ignoring concurrency\n");
+ concurrency = 1;
+ }
+ }
+
+ if (1 != concurrency)
+ {
+ PR_SetConcurrency(concurrency);
+ PR_fprintf(err, "Concurrency set to %u\n", concurrency);
+ }
+
+ PR_fprintf(err,
+ "All threads will be %s\n",
+ (PR_GLOBAL_THREAD == thread_scope) ? "GLOBAL" : "LOCAL");
+
+ PR_fprintf(err, "Client buffer size will be %u\n", buffer_size);
+
+ if (-1 != xport_buffer)
+ PR_fprintf(
+ err, "Transport send & receive buffer size will be %u\n", xport_buffer);
+
+
+ if (NULL == server_name) {
+ Server();
+ }
+ else {
+ Client(server_name);
+ }
+
+ return 0;
+} /* main */
+
+/* thruput.c */
+
diff --git a/nsprpub/pr/tests/time.c b/nsprpub/pr/tests/time.c
new file mode 100644
index 0000000000..cdb3ef73a8
--- /dev/null
+++ b/nsprpub/pr/tests/time.c
@@ -0,0 +1,177 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * Program to test different ways to get the time; right now it is tuned
+ * only for solaris.
+ * solaris results (100000 iterations):
+ * time to get time with time(): 4.63 usec avg, 463 msec total
+ * time to get time with gethrtime(): 2.17 usec avg, 217 msec total
+ * time to get time with gettimeofday(): 1.25 usec avg, 125 msec total
+ *
+ *
+ */
+/***********************************************************************
+** Includes
+***********************************************************************/
+/* Used to get the command line option */
+#include "plgetopt.h"
+
+#include "nspr.h"
+#include "prpriv.h"
+#include "prinrval.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+
+#define DEFAULT_COUNT 100000
+PRInt32 count;
+
+time_t itime;
+hrtime_t ihrtime;
+
+void
+ftime_init()
+{
+ itime = time(NULL);
+ ihrtime = gethrtime();
+}
+
+time_t
+ftime()
+{
+ hrtime_t now = gethrtime();
+
+ return itime + ((now - ihrtime) / 1000000000ll);
+}
+
+static void timeTime(void)
+{
+ PRInt32 index = count;
+ time_t rv;
+
+ for (; index--;) {
+ rv = time(NULL);
+ }
+}
+
+static void timeGethrtime(void)
+{
+ PRInt32 index = count;
+ time_t rv;
+
+ for (; index--;) {
+ rv = ftime();
+ }
+}
+
+static void timeGettimeofday(void)
+{
+ PRInt32 index = count;
+ time_t rv;
+ struct timeval tp;
+
+ for (; index--;) {
+ rv = gettimeofday(&tp, NULL);
+ }
+}
+
+static void timePRTime32(void)
+{
+ PRInt32 index = count;
+ PRInt32 rv32;
+ PRTime q;
+ PRTime rv;
+
+ LL_I2L(q, 1000000);
+
+ for (; index--;) {
+ rv = PR_Now();
+ LL_DIV(rv, rv, q);
+ LL_L2I(rv32, rv);
+ }
+}
+
+static void timePRTime64(void)
+{
+ PRInt32 index = count;
+ PRTime rv;
+
+ for (; index--;) {
+ rv = PR_Now();
+ }
+}
+
+/************************************************************************/
+
+static void Measure(void (*func)(void), const char *msg)
+{
+ PRIntervalTime start, stop;
+ double d;
+ PRInt32 tot;
+
+ start = PR_IntervalNow();
+ (*func)();
+ stop = PR_IntervalNow();
+
+ d = (double)PR_IntervalToMicroseconds(stop - start);
+ tot = PR_IntervalToMilliseconds(stop-start);
+
+ if (debug_mode) {
+ printf("%40s: %6.2f usec avg, %d msec total\n", msg, d / count, tot);
+ }
+}
+
+int main(int argc, char **argv)
+{
+ /* The command line argument: -d is used to determine if the test is being run
+ in debug mode. The regress tool requires only one line output:PASS or FAIL.
+ All of the printfs associated with this test has been handled with a if (debug_mode)
+ test.
+ Usage: test_name -d
+ */
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "d:");
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 'd': /* debug mode */
+ debug_mode = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
+ PR_STDIO_INIT();
+
+ if (argc > 1) {
+ count = atoi(argv[1]);
+ } else {
+ count = DEFAULT_COUNT;
+ }
+
+ ftime_init();
+
+ Measure(timeTime, "time to get time with time()");
+ Measure(timeGethrtime, "time to get time with gethrtime()");
+ Measure(timeGettimeofday, "time to get time with gettimeofday()");
+ Measure(timePRTime32, "time to get time with PR_Time() (32bit)");
+ Measure(timePRTime64, "time to get time with PR_Time() (64bit)");
+
+ PR_Cleanup();
+ return 0;
+}
+
+
+
diff --git a/nsprpub/pr/tests/timemac.c b/nsprpub/pr/tests/timemac.c
new file mode 100644
index 0000000000..b0f8b17d8a
--- /dev/null
+++ b/nsprpub/pr/tests/timemac.c
@@ -0,0 +1,112 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * file: timemac.c
+ * description: test time and date routines on the Mac
+ */
+#include <stdio.h>
+#include "prinit.h"
+#include "prtime.h"
+
+
+static char *dayOfWeek[] =
+{ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "???" };
+static char *month[] =
+{ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "???"
+};
+
+static void printExplodedTime(const PRExplodedTime *et) {
+ PRInt32 totalOffset;
+ PRInt32 hourOffset, minOffset;
+ const char *sign;
+
+ /* Print day of the week, month, day, hour, minute, and second */
+ printf( "%s %s %ld %02ld:%02ld:%02ld ",
+ dayOfWeek[et->tm_wday], month[et->tm_month], et->tm_mday,
+ et->tm_hour, et->tm_min, et->tm_sec);
+
+ /* Print time zone */
+ totalOffset = et->tm_params.tp_gmt_offset + et->tm_params.tp_dst_offset;
+ if (totalOffset == 0) {
+ printf("UTC ");
+ } else {
+ sign = "";
+ if (totalOffset < 0) {
+ totalOffset = -totalOffset;
+ sign = "-";
+ }
+ hourOffset = totalOffset / 3600;
+ minOffset = (totalOffset % 3600) / 60;
+ printf("%s%02ld%02ld ", sign, hourOffset, minOffset);
+ }
+
+ /* Print year */
+ printf("%d", et->tm_year);
+}
+
+int main(int argc, char** argv)
+{
+ PR_STDIO_INIT();
+ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
+
+
+ /*
+ *************************************************************
+ **
+ ** Testing PR_Now(), PR_ExplodeTime, and PR_ImplodeTime
+ ** on the current time
+ **
+ *************************************************************
+ */
+
+ {
+ PRTime t1, t2;
+ PRExplodedTime et;
+
+ printf("*********************************************\n");
+ printf("** **\n");
+ printf("** Testing PR_Now(), PR_ExplodeTime, and **\n");
+ printf("** PR_ImplodeTime on the current time **\n");
+ printf("** **\n");
+ printf("*********************************************\n\n");
+ t1 = PR_Now();
+
+ /* First try converting to UTC */
+
+ PR_ExplodeTime(t1, PR_GMTParameters, &et);
+ if (et.tm_params.tp_gmt_offset || et.tm_params.tp_dst_offset) {
+ printf("ERROR: UTC has nonzero gmt or dst offset.\n");
+ return 1;
+ }
+ printf("Current UTC is ");
+ printExplodedTime(&et);
+ printf("\n");
+
+ t2 = PR_ImplodeTime(&et);
+ if (LL_NE(t1, t2)) {
+ printf("ERROR: Explode and implode are NOT inverse.\n");
+ return 1;
+ }
+
+ /* Next, try converting to local (US Pacific) time */
+
+ PR_ExplodeTime(t1, PR_LocalTimeParameters, &et);
+ printf("Current local time is ");
+ printExplodedTime(&et);
+ printf("\n");
+ printf("GMT offset is %ld, DST offset is %ld\n",
+ et.tm_params.tp_gmt_offset, et.tm_params.tp_dst_offset);
+ t2 = PR_ImplodeTime(&et);
+ if (LL_NE(t1, t2)) {
+ printf("ERROR: Explode and implode are NOT inverse.\n");
+ return 1;
+ }
+ }
+
+ printf("Please examine the results\n");
+ return 0;
+}
diff --git a/nsprpub/pr/tests/timetest.c b/nsprpub/pr/tests/timetest.c
new file mode 100644
index 0000000000..9f96025d2f
--- /dev/null
+++ b/nsprpub/pr/tests/timetest.c
@@ -0,0 +1,823 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * file: timetest.c
+ * description: test time and date routines
+ */
+/***********************************************************************
+** Includes
+***********************************************************************/
+/* Used to get the command line option */
+#include "plgetopt.h"
+
+#include "prinit.h"
+#include "prtime.h"
+#include "prprf.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int failed_already=0;
+PRBool debug_mode = PR_FALSE;
+
+static char *dayOfWeek[] =
+{ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "???" };
+static char *month[] =
+{ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "???"
+};
+
+static void PrintExplodedTime(const PRExplodedTime *et) {
+ PRInt32 totalOffset;
+ PRInt32 hourOffset, minOffset;
+ const char *sign;
+
+ /* Print day of the week, month, day, hour, minute, and second */
+ if (debug_mode) printf("%s %s %ld %02ld:%02ld:%02ld ",
+ dayOfWeek[et->tm_wday], month[et->tm_month], et->tm_mday,
+ et->tm_hour, et->tm_min, et->tm_sec);
+
+ /* Print time zone */
+ totalOffset = et->tm_params.tp_gmt_offset + et->tm_params.tp_dst_offset;
+ if (totalOffset == 0) {
+ if (debug_mode) {
+ printf("UTC ");
+ }
+ } else {
+ sign = "+";
+ if (totalOffset < 0) {
+ totalOffset = -totalOffset;
+ sign = "-";
+ }
+ hourOffset = totalOffset / 3600;
+ minOffset = (totalOffset % 3600) / 60;
+ if (debug_mode) {
+ printf("%s%02ld%02ld ", sign, hourOffset, minOffset);
+ }
+ }
+
+ /* Print year */
+ if (debug_mode) {
+ printf("%hd", et->tm_year);
+ }
+}
+
+static int ExplodedTimeIsEqual(const PRExplodedTime *et1,
+ const PRExplodedTime *et2)
+{
+ if (et1->tm_usec == et2->tm_usec &&
+ et1->tm_sec == et2->tm_sec &&
+ et1->tm_min == et2->tm_min &&
+ et1->tm_hour == et2->tm_hour &&
+ et1->tm_mday == et2->tm_mday &&
+ et1->tm_month == et2->tm_month &&
+ et1->tm_year == et2->tm_year &&
+ et1->tm_wday == et2->tm_wday &&
+ et1->tm_yday == et2->tm_yday &&
+ et1->tm_params.tp_gmt_offset == et2->tm_params.tp_gmt_offset &&
+ et1->tm_params.tp_dst_offset == et2->tm_params.tp_dst_offset) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+static void
+testParseTimeString(PRTime t)
+{
+ PRExplodedTime et;
+ PRTime t2;
+ char timeString[128];
+ char buf[128];
+ PRInt32 totalOffset;
+ PRInt32 hourOffset, minOffset;
+ const char *sign;
+ PRInt64 usec_per_sec;
+
+ /* Truncate the microsecond part of PRTime */
+ LL_I2L(usec_per_sec, PR_USEC_PER_SEC);
+ LL_DIV(t, t, usec_per_sec);
+ LL_MUL(t, t, usec_per_sec);
+
+ PR_ExplodeTime(t, PR_LocalTimeParameters, &et);
+
+ /* Print day of the week, month, day, hour, minute, and second */
+ PR_snprintf(timeString, 128, "%s %s %ld %02ld:%02ld:%02ld ",
+ dayOfWeek[et.tm_wday], month[et.tm_month], et.tm_mday,
+ et.tm_hour, et.tm_min, et.tm_sec);
+ /* Print time zone */
+ totalOffset = et.tm_params.tp_gmt_offset + et.tm_params.tp_dst_offset;
+ if (totalOffset == 0) {
+ strcat(timeString, "GMT "); /* I wanted to use "UTC" here, but
+ * PR_ParseTimeString doesn't
+ * understand "UTC". */
+ } else {
+ sign = "+";
+ if (totalOffset < 0) {
+ totalOffset = -totalOffset;
+ sign = "-";
+ }
+ hourOffset = totalOffset / 3600;
+ minOffset = (totalOffset % 3600) / 60;
+ PR_snprintf(buf, 128, "%s%02ld%02ld ", sign, hourOffset, minOffset);
+ strcat(timeString, buf);
+ }
+ /* Print year */
+ PR_snprintf(buf, 128, "%hd", et.tm_year);
+ strcat(timeString, buf);
+
+ if (PR_ParseTimeString(timeString, PR_FALSE, &t2) == PR_FAILURE) {
+ fprintf(stderr, "PR_ParseTimeString() failed\n");
+ exit(1);
+ }
+ if (LL_NE(t, t2)) {
+ fprintf(stderr, "PR_ParseTimeString() incorrect\n");
+ PR_snprintf(buf, 128, "t is %lld, t2 is %lld, time string is %s\n",
+ t, t2, timeString);
+ fprintf(stderr, "%s\n", buf);
+ exit(1);
+ }
+}
+
+int main(int argc, char** argv)
+{
+ /* The command line argument: -d is used to determine if the test is being run
+ in debug mode. The regress tool requires only one line output:PASS or FAIL.
+ All of the printfs associated with this test has been handled with a if (debug_mode)
+ test.
+ Usage: test_name -d
+ */
+ PLOptStatus os;
+ PLOptState *opt;
+
+ PR_STDIO_INIT();
+ opt = PL_CreateOptState(argc, argv, "d");
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 'd': /* debug mode */
+ debug_mode = PR_TRUE;
+ break;
+ default:
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ /* main test */
+
+ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
+
+ /* Testing zero PRTime (the epoch) */
+ {
+ PRTime t;
+ PRExplodedTime et;
+
+ LL_I2L(t, 0);
+ if (debug_mode) {
+ printf("The NSPR epoch is:\n");
+ }
+ PR_ExplodeTime(t, PR_LocalTimeParameters, &et);
+ PrintExplodedTime(&et);
+ if (debug_mode) {
+ printf("\n");
+ }
+ PR_ExplodeTime(t, PR_GMTParameters, &et);
+ PrintExplodedTime(&et);
+ if (debug_mode) {
+ printf("\n\n");
+ }
+ testParseTimeString(t);
+ }
+
+ /*
+ *************************************************************
+ **
+ ** Testing PR_Now(), PR_ExplodeTime, and PR_ImplodeTime
+ ** on the current time
+ **
+ *************************************************************
+ */
+
+ {
+ PRTime t1, t2;
+ PRExplodedTime et;
+
+ if (debug_mode) {
+ printf("*********************************************\n");
+ printf("** **\n");
+ printf("** Testing PR_Now(), PR_ExplodeTime, and **\n");
+ printf("** PR_ImplodeTime on the current time **\n");
+ printf("** **\n");
+ printf("*********************************************\n\n");
+ }
+ t1 = PR_Now();
+
+ /* First try converting to UTC */
+
+ PR_ExplodeTime(t1, PR_GMTParameters, &et);
+ if (et.tm_params.tp_gmt_offset || et.tm_params.tp_dst_offset) {
+ if (debug_mode) {
+ printf("ERROR: UTC has nonzero gmt or dst offset.\n");
+ }
+ else {
+ failed_already=1;
+ }
+ return 1;
+ }
+ if (debug_mode) {
+ printf("Current UTC is ");
+ }
+ PrintExplodedTime(&et);
+ if (debug_mode) {
+ printf("\n");
+ }
+
+ t2 = PR_ImplodeTime(&et);
+ if (LL_NE(t1, t2)) {
+ if (debug_mode) {
+ printf("ERROR: Explode and implode are NOT inverse.\n");
+ }
+ else {
+ printf("FAIL\n");
+ }
+ return 1;
+ }
+
+ /* Next, try converting to local (US Pacific) time */
+
+ PR_ExplodeTime(t1, PR_LocalTimeParameters, &et);
+ if (debug_mode) {
+ printf("Current local time is ");
+ }
+ PrintExplodedTime(&et);
+ if (debug_mode) {
+ printf("\n");
+ }
+ if (debug_mode) printf("GMT offset is %ld, DST offset is %ld\n",
+ et.tm_params.tp_gmt_offset, et.tm_params.tp_dst_offset);
+ t2 = PR_ImplodeTime(&et);
+ if (LL_NE(t1, t2)) {
+ if (debug_mode) {
+ printf("ERROR: Explode and implode are NOT inverse.\n");
+ }
+ return 1;
+ }
+
+ if (debug_mode) {
+ printf("Please examine the results\n");
+ }
+ testParseTimeString(t1);
+ }
+
+
+ /*
+ *******************************************
+ **
+ ** Testing PR_NormalizeTime()
+ **
+ *******************************************
+ */
+
+ /* July 4, 2001 is Wednesday */
+ {
+ PRExplodedTime et;
+
+ if (debug_mode) {
+ printf("\n");
+ printf("**********************************\n");
+ printf("** **\n");
+ printf("** Testing PR_NormalizeTime() **\n");
+ printf("** **\n");
+ printf("**********************************\n\n");
+ }
+ et.tm_year = 2001;
+ et.tm_month = 7 - 1;
+ et.tm_mday = 4;
+ et.tm_hour = 0;
+ et.tm_min = 0;
+ et.tm_sec = 0;
+ et.tm_usec = 0;
+ et.tm_params = PR_GMTParameters(&et);
+
+ PR_NormalizeTime(&et, PR_GMTParameters);
+
+ if (debug_mode) {
+ printf("July 4, 2001 is %s.\n", dayOfWeek[et.tm_wday]);
+ }
+ if (et.tm_wday == 3) {
+ if (debug_mode) {
+ printf("PASS\n");
+ }
+ } else {
+ if (debug_mode) {
+ printf("ERROR: It should be Wednesday\n");
+ }
+ else {
+ failed_already=1;
+ }
+ return 1;
+ }
+ testParseTimeString(PR_ImplodeTime(&et));
+
+ /* June 12, 1997 23:00 PST == June 13, 1997 00:00 PDT */
+ et.tm_year = 1997;
+ et.tm_month = 6 - 1;
+ et.tm_mday = 12;
+ et.tm_hour = 23;
+ et.tm_min = 0;
+ et.tm_sec = 0;
+ et.tm_usec = 0;
+ et.tm_params.tp_gmt_offset = -8 * 3600;
+ et.tm_params.tp_dst_offset = 0;
+
+ PR_NormalizeTime(&et, PR_USPacificTimeParameters);
+
+ if (debug_mode) {
+ printf("Thu Jun 12, 1997 23:00:00 PST is ");
+ }
+ PrintExplodedTime(&et);
+ if (debug_mode) {
+ printf(".\n");
+ }
+ if (et.tm_wday == 5) {
+ if (debug_mode) {
+ printf("PASS\n");
+ }
+ } else {
+ if (debug_mode) {
+ printf("ERROR: It should be Friday\n");
+ }
+ else {
+ failed_already=1;
+ }
+ return 1;
+ }
+ testParseTimeString(PR_ImplodeTime(&et));
+
+ /* Feb 14, 1997 00:00:00 PDT == Feb 13, 1997 23:00:00 PST */
+ et.tm_year = 1997;
+ et.tm_month = 2 - 1;
+ et.tm_mday = 14;
+ et.tm_hour = 0;
+ et.tm_min = 0;
+ et.tm_sec = 0;
+ et.tm_usec = 0;
+ et.tm_params.tp_gmt_offset = -8 * 3600;
+ et.tm_params.tp_dst_offset = 3600;
+
+ PR_NormalizeTime(&et, PR_USPacificTimeParameters);
+
+ if (debug_mode) {
+ printf("Fri Feb 14, 1997 00:00:00 PDT is ");
+ }
+ PrintExplodedTime(&et);
+ if (debug_mode) {
+ printf(".\n");
+ }
+ if (et.tm_wday == 4) {
+ if (debug_mode) {
+ printf("PASS\n");
+ }
+ } else {
+ if (debug_mode) {
+ printf("ERROR: It should be Thursday\n");
+ }
+ else {
+ failed_already=1;
+ }
+ return 1;
+ }
+ testParseTimeString(PR_ImplodeTime(&et));
+
+ /* What time is Nov. 7, 1996, 18:29:23 PDT? */
+ et.tm_year = 1996;
+ et.tm_month = 11 - 1;
+ et.tm_mday = 7;
+ et.tm_hour = 18;
+ et.tm_min = 29;
+ et.tm_sec = 23;
+ et.tm_usec = 0;
+ et.tm_params.tp_gmt_offset = -8 * 3600; /* PDT */
+ et.tm_params.tp_dst_offset = 3600;
+
+ PR_NormalizeTime(&et, PR_LocalTimeParameters);
+ if (debug_mode) {
+ printf("Nov 7 18:29:23 PDT 1996 is ");
+ }
+ PrintExplodedTime(&et);
+ if (debug_mode) {
+ printf(".\n");
+ }
+ testParseTimeString(PR_ImplodeTime(&et));
+
+ /* What time is Oct. 7, 1995, 18:29:23 PST? */
+ et.tm_year = 1995;
+ et.tm_month = 10 - 1;
+ et.tm_mday = 7;
+ et.tm_hour = 18;
+ et.tm_min = 29;
+ et.tm_sec = 23;
+ et.tm_params.tp_gmt_offset = -8 * 3600; /* PST */
+ et.tm_params.tp_dst_offset = 0;
+
+ PR_NormalizeTime(&et, PR_LocalTimeParameters);
+ if (debug_mode) {
+ printf("Oct 7 18:29:23 PST 1995 is ");
+ }
+ PrintExplodedTime(&et);
+ if (debug_mode) {
+ printf(".\n");
+ }
+ testParseTimeString(PR_ImplodeTime(&et));
+
+ if (debug_mode) {
+ printf("Please examine the results\n");
+ }
+ }
+
+ /*
+ **************************************************************
+ **
+ ** Testing range of years
+ **
+ **************************************************************
+ */
+
+ {
+ PRExplodedTime et1, et2;
+ PRTime ttt;
+ PRTime secs;
+
+ if (debug_mode) {
+ printf("\n");
+ printf("***************************************\n");
+ printf("** **\n");
+ printf("** Testing range of years **\n");
+ printf("** **\n");
+ printf("***************************************\n\n");
+ }
+ /* April 4, 1917 GMT */
+ et1.tm_usec = 0;
+ et1.tm_sec = 0;
+ et1.tm_min = 0;
+ et1.tm_hour = 0;
+ et1.tm_mday = 4;
+ et1.tm_month = 4 - 1;
+ et1.tm_year = 1917;
+ et1.tm_params = PR_GMTParameters(&et1);
+ PR_NormalizeTime(&et1, PR_LocalTimeParameters);
+ secs = PR_ImplodeTime(&et1);
+ if (LL_GE_ZERO(secs)) {
+ if (debug_mode) {
+ printf("ERROR: April 4, 1917 GMT returns a nonnegative second count\n");
+ }
+ failed_already = 1;
+ return 1;
+ }
+ PR_ExplodeTime(secs, PR_LocalTimeParameters, &et2);
+ if (!ExplodedTimeIsEqual(&et1, &et2)) {
+ if (debug_mode) {
+ printf("ERROR: PR_ImplodeTime and PR_ExplodeTime are not inverse for April 4, 1917 GMT\n");
+ }
+ failed_already=1;
+ return 1;
+ }
+ ttt = PR_ImplodeTime(&et1);
+ testParseTimeString( ttt );
+
+ if (debug_mode) {
+ printf("Test passed for April 4, 1917\n");
+ }
+
+ /* July 4, 2050 */
+ et1.tm_usec = 0;
+ et1.tm_sec = 0;
+ et1.tm_min = 0;
+ et1.tm_hour = 0;
+ et1.tm_mday = 4;
+ et1.tm_month = 7 - 1;
+ et1.tm_year = 2050;
+ et1.tm_params = PR_GMTParameters(&et1);
+ PR_NormalizeTime(&et1, PR_LocalTimeParameters);
+ secs = PR_ImplodeTime(&et1);
+ if (!LL_GE_ZERO(secs)) {
+ if (debug_mode) {
+ printf("ERROR: July 4, 2050 GMT returns a negative second count\n");
+ }
+ failed_already = 1;
+ return 1;
+ }
+ PR_ExplodeTime(secs, PR_LocalTimeParameters, &et2);
+ if (!ExplodedTimeIsEqual(&et1, &et2)) {
+ if (debug_mode) {
+ printf("ERROR: PR_ImplodeTime and PR_ExplodeTime are not inverse for July 4, 2050 GMT\n");
+ }
+ failed_already=1;
+ return 1;
+ }
+ testParseTimeString(PR_ImplodeTime(&et1));
+
+ if (debug_mode) {
+ printf("Test passed for July 4, 2050\n");
+ }
+
+ }
+
+ /*
+ **************************************************************
+ **
+ ** Stress test
+ *
+ ** Go through four years, starting from
+ ** 00:00:00 PST Jan. 1, 2005, incrementing
+ ** every 10 minutes.
+ **
+ **************************************************************
+ */
+
+ {
+ PRExplodedTime et, et1, et2;
+ PRInt64 usecPer10Min;
+ int day, hour, min;
+ PRTime usecs;
+ int dstInEffect = 0;
+
+ if (debug_mode) {
+ printf("\n");
+ printf("*******************************************************\n");
+ printf("** **\n");
+ printf("** Stress test Pacific Time **\n");
+ printf("** Starting from midnight Jan. 1, 2005 PST, **\n");
+ printf("** going through four years in 10-minute increment **\n");
+ printf("** **\n");
+ printf("*******************************************************\n\n");
+ }
+ LL_I2L(usecPer10Min, 600000000L);
+
+ /* 00:00:00 PST Jan. 1, 2005 */
+ et.tm_usec = 0;
+ et.tm_sec = 0;
+ et.tm_min = 0;
+ et.tm_hour = 0;
+ et.tm_mday = 1;
+ et.tm_month = 0;
+ et.tm_year = 2005;
+ et.tm_params.tp_gmt_offset = -8 * 3600;
+ et.tm_params.tp_dst_offset = 0;
+ usecs = PR_ImplodeTime(&et);
+
+ for (day = 0; day < 4 * 365 + 1; day++) {
+ for (hour = 0; hour < 24; hour++) {
+ for (min = 0; min < 60; min += 10) {
+ LL_ADD(usecs, usecs, usecPer10Min);
+ PR_ExplodeTime(usecs, PR_USPacificTimeParameters, &et1);
+
+ et2 = et;
+ et2.tm_usec += 600000000L;
+ PR_NormalizeTime(&et2, PR_USPacificTimeParameters);
+
+ if (!ExplodedTimeIsEqual(&et1, &et2)) {
+ printf("ERROR: componentwise comparison failed\n");
+ PrintExplodedTime(&et1);
+ printf("\n");
+ PrintExplodedTime(&et2);
+ printf("\n");
+ failed_already=1;
+ return 1;
+ }
+
+ if (LL_NE(usecs, PR_ImplodeTime(&et1))) {
+ printf("ERROR: PR_ExplodeTime and PR_ImplodeTime are not inverse\n");
+ PrintExplodedTime(&et1);
+ printf("\n");
+ failed_already=1;
+ return 1;
+ }
+ testParseTimeString(usecs);
+
+ if (!dstInEffect && et1.tm_params.tp_dst_offset) {
+ dstInEffect = 1;
+ if (debug_mode) {
+ printf("DST changeover from ");
+ PrintExplodedTime(&et);
+ printf(" to ");
+ PrintExplodedTime(&et1);
+ printf(".\n");
+ }
+ } else if (dstInEffect && !et1.tm_params.tp_dst_offset) {
+ dstInEffect = 0;
+ if (debug_mode) {
+ printf("DST changeover from ");
+ PrintExplodedTime(&et);
+ printf(" to ");
+ PrintExplodedTime(&et1);
+ printf(".\n");
+ }
+ }
+
+ et = et1;
+ }
+ }
+ }
+ if (debug_mode) {
+ printf("Test passed\n");
+ }
+ }
+
+
+ /* Same stress test, but with PR_LocalTimeParameters */
+
+ {
+ PRExplodedTime et, et1, et2;
+ PRInt64 usecPer10Min;
+ int day, hour, min;
+ PRTime usecs;
+ int dstInEffect = 0;
+
+ if (debug_mode) {
+ printf("\n");
+ printf("*******************************************************\n");
+ printf("** **\n");
+ printf("** Stress test Local Time **\n");
+ printf("** Starting from midnight Jan. 1, 2005 PST, **\n");
+ printf("** going through four years in 10-minute increment **\n");
+ printf("** **\n");
+ printf("*******************************************************\n\n");
+ }
+
+ LL_I2L(usecPer10Min, 600000000L);
+
+ /* 00:00:00 PST Jan. 1, 2005 */
+ et.tm_usec = 0;
+ et.tm_sec = 0;
+ et.tm_min = 0;
+ et.tm_hour = 0;
+ et.tm_mday = 1;
+ et.tm_month = 0;
+ et.tm_year = 2005;
+ et.tm_params.tp_gmt_offset = -8 * 3600;
+ et.tm_params.tp_dst_offset = 0;
+ usecs = PR_ImplodeTime(&et);
+
+ for (day = 0; day < 4 * 365 + 1; day++) {
+ for (hour = 0; hour < 24; hour++) {
+ for (min = 0; min < 60; min += 10) {
+ LL_ADD(usecs, usecs, usecPer10Min);
+ PR_ExplodeTime(usecs, PR_LocalTimeParameters, &et1);
+
+ et2 = et;
+ et2.tm_usec += 600000000L;
+ PR_NormalizeTime(&et2, PR_LocalTimeParameters);
+
+ if (!ExplodedTimeIsEqual(&et1, &et2)) {
+ printf("ERROR: componentwise comparison failed\n");
+ PrintExplodedTime(&et1);
+ printf("\n");
+ PrintExplodedTime(&et2);
+ printf("\n");
+ return 1;
+ }
+
+ if (LL_NE(usecs, PR_ImplodeTime(&et1))) {
+ printf("ERROR: PR_ExplodeTime and PR_ImplodeTime are not inverse\n");
+ PrintExplodedTime(&et1);
+ printf("\n");
+ failed_already=1;
+ return 1;
+ }
+ testParseTimeString(usecs);
+
+ if (!dstInEffect && et1.tm_params.tp_dst_offset) {
+ dstInEffect = 1;
+ if (debug_mode) {
+ printf("DST changeover from ");
+ PrintExplodedTime(&et);
+ printf(" to ");
+ PrintExplodedTime(&et1);
+ printf(".\n");
+ }
+ } else if (dstInEffect && !et1.tm_params.tp_dst_offset) {
+ dstInEffect = 0;
+ if (debug_mode) {
+ printf("DST changeover from ");
+ PrintExplodedTime(&et);
+ printf(" to ");
+ PrintExplodedTime(&et1);
+ printf(".\n");
+ }
+ }
+
+ et = et1;
+ }
+ }
+ }
+ if (debug_mode) {
+ printf("Test passed\n");
+ }
+ }
+
+ /* Same stress test, but with PR_LocalTimeParameters and going backward */
+
+ {
+ PRExplodedTime et, et1, et2;
+ PRInt64 usecPer10Min;
+ int day, hour, min;
+ PRTime usecs;
+ int dstInEffect = 0;
+
+ if (debug_mode) {
+ printf("\n");
+ printf("*******************************************************\n");
+ printf("** **\n");
+ printf("** Stress test Local Time **\n");
+ printf("** Starting from midnight Jan. 1, 2009 PST, **\n");
+ printf("** going back four years in 10-minute increment **\n");
+ printf("** **\n");
+ printf("*******************************************************\n\n");
+ }
+
+ LL_I2L(usecPer10Min, 600000000L);
+
+ /* 00:00:00 PST Jan. 1, 2009 */
+ et.tm_usec = 0;
+ et.tm_sec = 0;
+ et.tm_min = 0;
+ et.tm_hour = 0;
+ et.tm_mday = 1;
+ et.tm_month = 0;
+ et.tm_year = 2009;
+ et.tm_params.tp_gmt_offset = -8 * 3600;
+ et.tm_params.tp_dst_offset = 0;
+ usecs = PR_ImplodeTime(&et);
+
+ for (day = 0; day < 4 * 365 + 1; day++) {
+ for (hour = 0; hour < 24; hour++) {
+ for (min = 0; min < 60; min += 10) {
+ LL_SUB(usecs, usecs, usecPer10Min);
+ PR_ExplodeTime(usecs, PR_LocalTimeParameters, &et1);
+
+ et2 = et;
+ et2.tm_usec -= 600000000L;
+ PR_NormalizeTime(&et2, PR_LocalTimeParameters);
+
+ if (!ExplodedTimeIsEqual(&et1, &et2)) {
+ printf("ERROR: componentwise comparison failed\n");
+ PrintExplodedTime(&et1);
+ printf("\n");
+ PrintExplodedTime(&et2);
+ printf("\n");
+ return 1;
+ }
+
+ if (LL_NE(usecs, PR_ImplodeTime(&et1))) {
+ printf("ERROR: PR_ExplodeTime and PR_ImplodeTime are not inverse\n");
+ PrintExplodedTime(&et1);
+ printf("\n");
+ failed_already=1;
+ return 1;
+ }
+ testParseTimeString(usecs);
+
+ if (!dstInEffect && et1.tm_params.tp_dst_offset) {
+ dstInEffect = 1;
+ if (debug_mode) {
+ printf("DST changeover from ");
+ PrintExplodedTime(&et);
+ printf(" to ");
+ PrintExplodedTime(&et1);
+ printf(".\n");
+ }
+ } else if (dstInEffect && !et1.tm_params.tp_dst_offset) {
+ dstInEffect = 0;
+ if (debug_mode) {
+ printf("DST changeover from ");
+ PrintExplodedTime(&et);
+ printf(" to ");
+ PrintExplodedTime(&et1);
+ printf(".\n");
+ }
+ }
+
+ et = et1;
+ }
+ }
+ }
+ }
+
+ if (failed_already) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+
+}
diff --git a/nsprpub/pr/tests/tmoacc.c b/nsprpub/pr/tests/tmoacc.c
new file mode 100644
index 0000000000..d7e64cbea6
--- /dev/null
+++ b/nsprpub/pr/tests/tmoacc.c
@@ -0,0 +1,339 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nspr.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "plerror.h"
+#include "plgetopt.h"
+
+#ifdef DEBUG
+#define PORT_INC_DO +100
+#else
+#define PORT_INC_DO
+#endif
+#ifdef IS_64
+#define PORT_INC_3264 +200
+#else
+#define PORT_INC_3264
+#endif
+
+#define BASE_PORT 9867 PORT_INC_DO PORT_INC_3264
+#define DEFAULT_THREADS 1
+#define DEFAULT_BACKLOG 10
+#define DEFAULT_TIMEOUT 10
+#define RANDOM_RANGE 100 /* should be significantly smaller than RAND_MAX */
+
+typedef enum {running, stopped} Status;
+
+typedef struct Shared
+{
+ PRLock *ml;
+ PRCondVar *cv;
+ PRBool passed;
+ PRBool random;
+ PRFileDesc *debug;
+ PRIntervalTime timeout;
+ PRFileDesc *listenSock;
+ Status status;
+} Shared;
+
+static PRIntervalTime Timeout(const Shared *shared)
+{
+ PRIntervalTime timeout = shared->timeout;
+ if (shared->random)
+ {
+ PRIntervalTime half = timeout >> 1; /* one half of the interval */
+ PRIntervalTime quarter = half >> 1; /* one quarter of the interval */
+ /* something in [0..timeout / 2) */
+ PRUint32 random = (rand() % RANDOM_RANGE) * half / RANDOM_RANGE;
+ timeout = (3 * quarter) + random; /* [75..125)% */
+ }
+ return timeout;
+} /* Timeout */
+
+static void Accept(void *arg)
+{
+ PRStatus rv;
+ char *buffer = NULL;
+ PRNetAddr clientAddr;
+ Shared *shared = (Shared*)arg;
+ PRInt32 recv_length = 0, flags = 0;
+ PRFileDesc *clientSock;
+ PRIntn toread, byte, bytes, loop = 0;
+ struct Descriptor {
+ PRInt32 length;
+ PRUint32 checksum;
+ } descriptor;
+
+ do
+ {
+ PRUint32 checksum = 0;
+ if (NULL != shared->debug) {
+ PR_fprintf(shared->debug, "[%d]accepting ... ", loop++);
+ }
+ clientSock = PR_Accept(
+ shared->listenSock, &clientAddr, Timeout(shared));
+ if (clientSock != NULL)
+ {
+ if (NULL != shared->debug) {
+ PR_fprintf(shared->debug, "reading length ... ");
+ }
+ bytes = PR_Recv(
+ clientSock, &descriptor, sizeof(descriptor),
+ flags, Timeout(shared));
+ if (sizeof(descriptor) == bytes)
+ {
+ /* and, before doing something stupid ... */
+ descriptor.length = PR_ntohl(descriptor.length);
+ descriptor.checksum = PR_ntohl(descriptor.checksum);
+ if (NULL != shared->debug) {
+ PR_fprintf(shared->debug, "%d bytes ... ", descriptor.length);
+ }
+ toread = descriptor.length;
+ if (recv_length < descriptor.length)
+ {
+ if (NULL != buffer) {
+ PR_DELETE(buffer);
+ }
+ buffer = (char*)PR_MALLOC(descriptor.length);
+ recv_length = descriptor.length;
+ }
+ for (toread = descriptor.length; toread > 0; toread -= bytes)
+ {
+ bytes = PR_Recv(
+ clientSock, &buffer[descriptor.length - toread],
+ toread, flags, Timeout(shared));
+ if (-1 == bytes)
+ {
+ if (NULL != shared->debug) {
+ PR_fprintf(shared->debug, "read data failed...");
+ }
+ bytes = 0;
+ }
+ }
+ }
+ else if (NULL != shared->debug)
+ {
+ PR_fprintf(shared->debug, "read desciptor failed...");
+ descriptor.length = -1;
+ }
+ if (NULL != shared->debug) {
+ PR_fprintf(shared->debug, "closing");
+ }
+ rv = PR_Shutdown(clientSock, PR_SHUTDOWN_BOTH);
+ if ((PR_FAILURE == rv) && (NULL != shared->debug))
+ {
+ PR_fprintf(shared->debug, " failed");
+ shared->passed = PR_FALSE;
+ }
+ rv = PR_Close(clientSock);
+ if (PR_FAILURE == rv) if (NULL != shared->debug)
+ {
+ PR_fprintf(shared->debug, " failed");
+ shared->passed = PR_FALSE;
+ }
+ if (descriptor.length > 0)
+ {
+ for (byte = 0; byte < descriptor.length; ++byte)
+ {
+ PRUint32 overflow = checksum & 0x80000000;
+ checksum = (checksum << 1);
+ if (0x00000000 != overflow) {
+ checksum += 1;
+ }
+ checksum += buffer[byte];
+ }
+ if ((descriptor.checksum != checksum) && (NULL != shared->debug))
+ {
+ PR_fprintf(shared->debug, " ... data mismatch");
+ shared->passed = PR_FALSE;
+ }
+ }
+ else if (0 == descriptor.length)
+ {
+ PR_Lock(shared->ml);
+ shared->status = stopped;
+ PR_NotifyCondVar(shared->cv);
+ PR_Unlock(shared->ml);
+ }
+ if (NULL != shared->debug) {
+ PR_fprintf(shared->debug, "\n");
+ }
+ }
+ else
+ {
+ if (PR_PENDING_INTERRUPT_ERROR != PR_GetError())
+ {
+ if (NULL != shared->debug) {
+ PL_PrintError("Accept");
+ }
+ shared->passed = PR_FALSE;
+ }
+ }
+ } while (running == shared->status);
+ if (NULL != buffer) {
+ PR_DELETE(buffer);
+ }
+} /* Accept */
+
+PRIntn Tmoacc(PRIntn argc, char **argv)
+{
+ PRStatus rv;
+ PRIntn exitStatus;
+ PRIntn index;
+ Shared *shared;
+ PLOptStatus os;
+ PRThread **thread;
+ PRNetAddr listenAddr;
+ PRSocketOptionData sockOpt;
+ PRIntn timeout = DEFAULT_TIMEOUT;
+ PRIntn threads = DEFAULT_THREADS;
+ PRIntn backlog = DEFAULT_BACKLOG;
+ PRThreadScope thread_scope = PR_LOCAL_THREAD;
+
+ PLOptState *opt = PL_CreateOptState(argc, argv, "dGb:t:T:R");
+
+ shared = PR_NEWZAP(Shared);
+
+ shared->debug = NULL;
+ shared->passed = PR_TRUE;
+ shared->random = PR_TRUE;
+ shared->status = running;
+ shared->ml = PR_NewLock();
+ shared->cv = PR_NewCondVar(shared->ml);
+
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 'd': /* debug mode */
+ shared->debug = PR_GetSpecialFD(PR_StandardError);
+ break;
+ case 'G': /* use global threads */
+ thread_scope = PR_GLOBAL_THREAD;
+ break;
+ case 'b': /* size of listen backlog */
+ backlog = atoi(opt->value);
+ break;
+ case 't': /* number of threads doing accept */
+ threads = atoi(opt->value);
+ break;
+ case 'T': /* timeout used for network operations */
+ timeout = atoi(opt->value);
+ break;
+ case 'R': /* randomize the timeout values */
+ shared->random = PR_TRUE;
+ break;
+ default:
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+ if (0 == threads) {
+ threads = DEFAULT_THREADS;
+ }
+ if (0 == backlog) {
+ backlog = DEFAULT_BACKLOG;
+ }
+ 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);
+
+ shared->timeout = PR_SecondsToInterval(timeout);
+
+ /* First bind to the socket */
+ shared->listenSock = PR_NewTCPSocket();
+ if (shared->listenSock)
+ {
+ sockOpt.option = PR_SockOpt_Reuseaddr;
+ sockOpt.value.reuse_addr = PR_TRUE;
+ rv = PR_SetSocketOption(shared->listenSock, &sockOpt);
+ PR_ASSERT(PR_SUCCESS == rv);
+ rv = PR_Bind(shared->listenSock, &listenAddr);
+ if (rv != PR_FAILURE)
+ {
+ rv = PR_Listen(shared->listenSock, threads + backlog);
+ if (PR_SUCCESS == rv)
+ {
+ thread = (PRThread**)PR_CALLOC(threads * sizeof(PRThread*));
+ for (index = 0; index < threads; ++index)
+ {
+ thread[index] = PR_CreateThread(
+ PR_USER_THREAD, Accept, shared,
+ PR_PRIORITY_NORMAL, thread_scope,
+ PR_JOINABLE_THREAD, 0);
+ PR_ASSERT(NULL != thread[index]);
+ }
+
+ PR_Lock(shared->ml);
+ while (shared->status == running) {
+ PR_WaitCondVar(shared->cv, PR_INTERVAL_NO_TIMEOUT);
+ }
+ PR_Unlock(shared->ml);
+ for (index = 0; index < threads; ++index)
+ {
+ rv = PR_Interrupt(thread[index]);
+ PR_ASSERT(PR_SUCCESS== rv);
+ rv = PR_JoinThread(thread[index]);
+ PR_ASSERT(PR_SUCCESS== rv);
+ }
+ PR_DELETE(thread);
+ }
+ else
+ {
+ if (shared->debug) {
+ PL_PrintError("Listen");
+ }
+ shared->passed = PR_FALSE;
+ }
+ }
+ else
+ {
+ if (shared->debug) {
+ PL_PrintError("Bind");
+ }
+ shared->passed = PR_FALSE;
+ }
+
+ PR_Close(shared->listenSock);
+ }
+ else
+ {
+ if (shared->debug) {
+ PL_PrintError("Create");
+ }
+ shared->passed = PR_FALSE;
+ }
+
+ PR_DestroyCondVar(shared->cv);
+ PR_DestroyLock(shared->ml);
+
+ PR_fprintf(
+ PR_GetSpecialFD(PR_StandardError), "%s\n",
+ ((shared->passed) ? "PASSED" : "FAILED"));
+
+ exitStatus = (shared->passed) ? 0 : 1;
+ PR_DELETE(shared);
+ return exitStatus;
+}
+
+int main(int argc, char **argv)
+{
+ return (PR_VersionCheck(PR_VERSION)) ?
+ PR_Initialize(Tmoacc, argc, argv, 4) : -1;
+} /* main */
+
+/* tmoacc */
diff --git a/nsprpub/pr/tests/tmocon.c b/nsprpub/pr/tests/tmocon.c
new file mode 100644
index 0000000000..3d992c3443
--- /dev/null
+++ b/nsprpub/pr/tests/tmocon.c
@@ -0,0 +1,435 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/***********************************************************************
+**
+** Name: tmocon.c
+**
+** Description: test client socket connection.
+**
+** Modification History:
+** 19-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
+** The debug mode will print all of the printfs associated with this test.
+** The regress mode will be the default mode. Since the regress tool limits
+** the output to a one line status:PASS or FAIL,all of the printf statements
+** have been handled with an if (debug_mode) statement.
+***********************************************************************/
+
+/***********************************************************************
+** Includes
+***********************************************************************/
+/* Used to get the command line option */
+#include "plgetopt.h"
+
+#include "nspr.h"
+#include "pprio.h"
+
+#include "plerror.h"
+#include "plgetopt.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* for getcwd */
+#if defined(XP_UNIX) || defined (XP_OS2)
+#include <unistd.h>
+#elif defined(XP_PC)
+#include <direct.h>
+#endif
+
+#ifdef WINCE
+#include <windows.h>
+char *getcwd(char *buf, size_t size)
+{
+ wchar_t wpath[MAX_PATH];
+ _wgetcwd(wpath, MAX_PATH);
+ WideCharToMultiByte(CP_ACP, 0, wpath, -1, buf, size, 0, 0);
+}
+#endif
+
+#ifdef DEBUG
+#define PORT_INC_DO +100
+#else
+#define PORT_INC_DO
+#endif
+#ifdef IS_64
+#define PORT_INC_3264 +200
+#else
+#define PORT_INC_3264
+#endif
+
+#define BASE_PORT 9867 PORT_INC_DO PORT_INC_3264
+
+#define DEFAULT_DALLY 1
+#define DEFAULT_THREADS 1
+#define DEFAULT_TIMEOUT 10
+#define DEFAULT_MESSAGES 100
+#define DEFAULT_MESSAGESIZE 100
+
+static PRFileDesc *debug_out = NULL;
+
+typedef struct Shared
+{
+ PRBool random;
+ PRBool failed;
+ PRBool intermittant;
+ PRIntn debug;
+ PRInt32 messages;
+ PRIntervalTime dally;
+ PRIntervalTime timeout;
+ PRInt32 message_length;
+ PRNetAddr serverAddress;
+} Shared;
+
+static PRIntervalTime Timeout(const Shared *shared)
+{
+ PRIntervalTime timeout = shared->timeout;
+ if (shared->random)
+ {
+ PRIntervalTime quarter = timeout >> 2; /* one quarter of the interval */
+ PRUint32 random = rand() % quarter; /* something in[0..timeout / 4) */
+ timeout = (((3 * quarter) + random) >> 2) + quarter; /* [75..125)% */
+ }
+ return timeout;
+} /* Timeout */
+
+static void CauseTimeout(const Shared *shared)
+{
+ if (shared->intermittant) {
+ PR_Sleep(Timeout(shared));
+ }
+} /* CauseTimeout */
+
+static PRStatus MakeReceiver(Shared *shared)
+{
+ PRStatus rv = PR_FAILURE;
+ if (PR_IsNetAddrType(&shared->serverAddress, PR_IpAddrLoopback))
+ {
+ char *argv[3];
+ char path[1024 + sizeof("/tmoacc")];
+
+ getcwd(path, sizeof(path));
+
+ (void)strcat(path, "/tmoacc");
+#ifdef XP_PC
+ (void)strcat(path, ".exe");
+#endif
+ argv[0] = path;
+ if (shared->debug > 0)
+ {
+ argv[1] = "-d";
+ argv[2] = NULL;
+ }
+ else {
+ argv[1] = NULL;
+ }
+ if (shared->debug > 1) {
+ PR_fprintf(debug_out, " creating accept process %s ...", path);
+ }
+ fflush(stdout);
+ rv = PR_CreateProcessDetached(path, argv, NULL, NULL);
+ if (PR_SUCCESS == rv)
+ {
+ if (shared->debug > 1) {
+ PR_fprintf(debug_out, " wait 5 seconds");
+ }
+ if (shared->debug > 1) {
+ PR_fprintf(debug_out, " before connecting to accept process ...");
+ }
+ fflush(stdout);
+ PR_Sleep(PR_SecondsToInterval(5));
+ return rv;
+ }
+ shared->failed = PR_TRUE;
+ if (shared->debug > 0) {
+ PL_FPrintError(debug_out, "PR_CreateProcessDetached failed");
+ }
+ }
+ return rv;
+} /* MakeReceiver */
+
+static void Connect(void *arg)
+{
+ PRStatus rv;
+ char *buffer = NULL;
+ PRFileDesc *clientSock;
+ Shared *shared = (Shared*)arg;
+ PRInt32 loop, bytes, flags = 0;
+ struct Descriptor {
+ PRInt32 length;
+ PRUint32 checksum;
+ } descriptor;
+ debug_out = (0 == shared->debug) ? NULL : PR_GetSpecialFD(PR_StandardError);
+
+ buffer = (char*)PR_MALLOC(shared->message_length);
+
+ for (bytes = 0; bytes < shared->message_length; ++bytes) {
+ buffer[bytes] = (char)bytes;
+ }
+
+ descriptor.checksum = 0;
+ for (bytes = 0; bytes < shared->message_length; ++bytes)
+ {
+ PRUint32 overflow = descriptor.checksum & 0x80000000;
+ descriptor.checksum = (descriptor.checksum << 1);
+ if (0x00000000 != overflow) {
+ descriptor.checksum += 1;
+ }
+ descriptor.checksum += buffer[bytes];
+ }
+ descriptor.checksum = PR_htonl(descriptor.checksum);
+
+ for (loop = 0; loop < shared->messages; ++loop)
+ {
+ if (shared->debug > 1) {
+ PR_fprintf(debug_out, "[%d]socket ... ", loop);
+ }
+ clientSock = PR_NewTCPSocket();
+ if (clientSock)
+ {
+ /*
+ * We need to slow down the rate of generating connect requests,
+ * otherwise the listen backlog queue on the accept side may
+ * become full and we will get connection refused or timeout
+ * error.
+ */
+
+ PR_Sleep(shared->dally);
+ 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)
+ {
+ PRInt32 descriptor_length = (loop < (shared->messages - 1)) ?
+ shared->message_length : 0;
+ descriptor.length = PR_htonl(descriptor_length);
+ if (shared->debug > 1)
+ PR_fprintf(
+ debug_out, "sending %d bytes ... ", descriptor_length);
+ CauseTimeout(shared); /* might cause server to timeout */
+ bytes = PR_Send(
+ clientSock, &descriptor, sizeof(descriptor),
+ flags, Timeout(shared));
+ if (bytes != sizeof(descriptor))
+ {
+ shared->failed = PR_TRUE;
+ if (shared->debug > 0) {
+ PL_FPrintError(debug_out, "PR_Send failed");
+ }
+ }
+ if (0 != descriptor_length)
+ {
+ CauseTimeout(shared);
+ bytes = PR_Send(
+ clientSock, buffer, descriptor_length,
+ flags, Timeout(shared));
+ if (bytes != descriptor_length)
+ {
+ shared->failed = PR_TRUE;
+ if (shared->debug > 0) {
+ PL_FPrintError(debug_out, "PR_Send failed");
+ }
+ }
+ }
+ if (shared->debug > 1) {
+ PR_fprintf(debug_out, "closing ... ");
+ }
+ rv = PR_Shutdown(clientSock, PR_SHUTDOWN_BOTH);
+ rv = PR_Close(clientSock);
+ if (shared->debug > 1)
+ {
+ if (PR_SUCCESS == rv) {
+ PR_fprintf(debug_out, "\n");
+ }
+ else {
+ PL_FPrintError(debug_out, "shutdown failed");
+ }
+ }
+ }
+ else
+ {
+ if (shared->debug > 1) {
+ PL_FPrintError(debug_out, "connect failed");
+ }
+ PR_Close(clientSock);
+ if ((loop == 0) && (PR_GetError() == PR_CONNECT_REFUSED_ERROR))
+ {
+ if (MakeReceiver(shared) == PR_FAILURE) {
+ break;
+ }
+ }
+ else
+ {
+ if (shared->debug > 1) {
+ PR_fprintf(debug_out, " exiting\n");
+ }
+ break;
+ }
+ }
+ }
+ else
+ {
+ shared->failed = PR_TRUE;
+ if (shared->debug > 0) {
+ PL_FPrintError(debug_out, "create socket");
+ }
+ break;
+ }
+ }
+
+ PR_DELETE(buffer);
+} /* Connect */
+
+int Tmocon(int argc, char **argv)
+{
+ /*
+ * USAGE
+ * -d turn on debugging output (default = off)
+ * -v turn on verbose output (default = off)
+ * -h <n> dns name of host serving the connection (default = self)
+ * -i dally intermittantly to cause timeouts (default = off)
+ * -m <n> number of messages to send (default = 100)
+ * -s <n> size of each message (default = 100)
+ * -t <n> number of threads sending (default = 1)
+ * -G use global threads (default = local)
+ * -T <n> timeout on I/O operations (seconds) (default = 10)
+ * -D <n> dally between connect requests (seconds)(default = 0)
+ * -R randomize the dally types around 'T' (default = no)
+ */
+
+ PRStatus rv;
+ int exitStatus;
+ PLOptStatus os;
+ Shared *shared = NULL;
+ PRThread **thread = NULL;
+ PRIntn index, threads = DEFAULT_THREADS;
+ PRThreadScope thread_scope = PR_LOCAL_THREAD;
+ PRInt32 dally = DEFAULT_DALLY, timeout = DEFAULT_TIMEOUT;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "divGRh:m:s:t:T:D:");
+
+ shared = PR_NEWZAP(Shared);
+
+ shared->debug = 0;
+ shared->failed = PR_FALSE;
+ shared->random = PR_FALSE;
+ shared->messages = DEFAULT_MESSAGES;
+ 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);
+
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 'd':
+ if (0 == shared->debug) {
+ shared->debug = 1;
+ }
+ break;
+ case 'v':
+ if (0 == shared->debug) {
+ shared->debug = 2;
+ }
+ break;
+ case 'i':
+ shared->intermittant = PR_TRUE;
+ break;
+ case 'R':
+ shared->random = PR_TRUE;
+ break;
+ case 'G':
+ thread_scope = PR_GLOBAL_THREAD;
+ break;
+ case 'h': /* the value for backlock */
+ {
+ 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 */
+ shared->messages = atoi(opt->value);
+ break;
+ case 't': /* number of threads sending */
+ threads = atoi(opt->value);
+ break;
+ case 'D': /* dally time between transmissions */
+ dally = atoi(opt->value);
+ break;
+ case 'T': /* timeout on I/O operations */
+ timeout = atoi(opt->value);
+ break;
+ case 's': /* total size of each message */
+ shared->message_length = atoi(opt->value);
+ break;
+ default:
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ if (0 == timeout) {
+ timeout = DEFAULT_TIMEOUT;
+ }
+ if (0 == threads) {
+ threads = DEFAULT_THREADS;
+ }
+ if (0 == shared->messages) {
+ shared->messages = DEFAULT_MESSAGES;
+ }
+ if (0 == shared->message_length) {
+ shared->message_length = DEFAULT_MESSAGESIZE;
+ }
+
+ shared->dally = PR_SecondsToInterval(dally);
+ shared->timeout = PR_SecondsToInterval(timeout);
+
+ thread = (PRThread**)PR_CALLOC(threads * sizeof(PRThread*));
+
+ for (index = 0; index < threads; ++index)
+ thread[index] = PR_CreateThread(
+ PR_USER_THREAD, Connect, shared,
+ PR_PRIORITY_NORMAL, thread_scope,
+ PR_JOINABLE_THREAD, 0);
+ for (index = 0; index < threads; ++index) {
+ rv = PR_JoinThread(thread[index]);
+ }
+
+ PR_DELETE(thread);
+
+ PR_fprintf(
+ PR_GetSpecialFD(PR_StandardError), "%s\n",
+ ((shared->failed) ? "FAILED" : "PASSED"));
+ exitStatus = (shared->failed) ? 1 : 0;
+ PR_DELETE(shared);
+ return exitStatus;
+}
+
+int main(int argc, char **argv)
+{
+ return (PR_VersionCheck(PR_VERSION)) ?
+ PR_Initialize(Tmocon, argc, argv, 4) : -1;
+} /* main */
+
+/* tmocon.c */
+
+
diff --git a/nsprpub/pr/tests/tpd.c b/nsprpub/pr/tests/tpd.c
new file mode 100644
index 0000000000..cac8c59aaa
--- /dev/null
+++ b/nsprpub/pr/tests/tpd.c
@@ -0,0 +1,308 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+** File: tpd.c
+** Description: Exercising the thread private data bailywick.
+*/
+
+#include "prmem.h"
+#include "prinit.h"
+#include "prlog.h"
+#include "prprf.h"
+#include "prthread.h"
+#include "prtypes.h"
+
+#include "private/pprio.h"
+
+#include "plgetopt.h"
+
+static PRUintn key[128];
+static PRIntn debug = 0;
+static PRBool failed = PR_FALSE;
+static PRBool should = PR_TRUE;
+static PRBool did = PR_TRUE;
+static PRFileDesc *fout = NULL;
+
+static void PrintProgress(PRIntn line)
+{
+ failed = failed || (should && !did);
+ failed = failed || (!should && did);
+ if (debug > 0)
+ {
+#if defined(WIN16)
+ printf(
+ "@ line %d destructor should%s have been called and was%s\n",
+ line, ((should) ? "" : " NOT"), ((did) ? "" : " NOT"));
+#else
+ PR_fprintf(
+ fout, "@ line %d destructor should%s have been called and was%s\n",
+ line, ((should) ? "" : " NOT"), ((did) ? "" : " NOT"));
+#endif
+ }
+} /* PrintProgress */
+
+static void MyAssert(const char *expr, const char *file, PRIntn line)
+{
+ if (debug > 0) {
+ (void)PR_fprintf(fout, "'%s' in file: %s: %d\n", expr, file, line);
+ }
+} /* MyAssert */
+
+#define MY_ASSERT(_expr) \
+ ((_expr)?((void)0):MyAssert(# _expr,__FILE__,__LINE__))
+
+
+static void PR_CALLBACK Destructor(void *data)
+{
+ MY_ASSERT(NULL != data);
+ if (should) {
+ did = PR_TRUE;
+ }
+ else {
+ failed = PR_TRUE;
+ }
+ /*
+ * We don't actually free the storage since it's actually allocated
+ * on the stack. Normally, this would not be the case and this is
+ * the opportunity to free whatever.
+ PR_Free(data);
+ */
+} /* Destructor */
+
+static void PR_CALLBACK Thread(void *null)
+{
+ void *pd;
+ PRStatus rv;
+ PRUintn keys;
+ char *key_string[] = {
+ "Key #0", "Key #1", "Key #2", "Key #3",
+ "Bogus #5", "Bogus #6", "Bogus #7", "Bogus #8"
+ };
+
+ did = should = PR_FALSE;
+ for (keys = 0; keys < 8; ++keys)
+ {
+ pd = PR_GetThreadPrivate(key[keys]);
+ MY_ASSERT(NULL == pd);
+ }
+ PrintProgress(__LINE__);
+
+ did = should = PR_FALSE;
+ for (keys = 0; keys < 4; ++keys)
+ {
+ rv = PR_SetThreadPrivate(key[keys], key_string[keys]);
+ MY_ASSERT(PR_SUCCESS == rv);
+ }
+ PrintProgress(__LINE__);
+
+ did = should = PR_FALSE;
+ for (keys = 4; keys < 8; ++keys)
+ {
+ rv = PR_SetThreadPrivate(key[keys], key_string[keys]);
+ MY_ASSERT(PR_FAILURE == rv);
+ }
+ PrintProgress(__LINE__);
+
+ did = PR_FALSE; should = PR_TRUE;
+ for (keys = 0; keys < 4; ++keys)
+ {
+ rv = PR_SetThreadPrivate(key[keys], key_string[keys]);
+ MY_ASSERT(PR_SUCCESS == rv);
+ }
+ PrintProgress(__LINE__);
+
+ did = PR_FALSE; should = PR_TRUE;
+ for (keys = 0; keys < 4; ++keys)
+ {
+ rv = PR_SetThreadPrivate(key[keys], NULL);
+ MY_ASSERT(PR_SUCCESS == rv);
+ }
+ PrintProgress(__LINE__);
+
+ did = should = PR_FALSE;
+ for (keys = 0; keys < 4; ++keys)
+ {
+ rv = PR_SetThreadPrivate(key[keys], NULL);
+ MY_ASSERT(PR_SUCCESS == rv);
+ }
+ PrintProgress(__LINE__);
+
+ did = should = PR_FALSE;
+ for (keys = 8; keys < 127; ++keys)
+ {
+ rv = PR_SetThreadPrivate(key[keys], "EXTENSION");
+ MY_ASSERT(PR_SUCCESS == rv);
+ }
+ PrintProgress(__LINE__);
+
+ did = PR_FALSE; should = PR_TRUE;
+ for (keys = 8; keys < 127; ++keys)
+ {
+ rv = PR_SetThreadPrivate(key[keys], NULL);
+ MY_ASSERT(PR_SUCCESS == rv);
+ }
+ PrintProgress(__LINE__);
+
+ did = should = PR_FALSE;
+ for (keys = 8; keys < 127; ++keys)
+ {
+ rv = PR_SetThreadPrivate(key[keys], NULL);
+ MY_ASSERT(PR_SUCCESS == rv);
+ }
+
+ /* put in keys and leave them there for thread exit */
+ did = should = PR_FALSE;
+ for (keys = 0; keys < 4; ++keys)
+ {
+ rv = PR_SetThreadPrivate(key[keys], key_string[keys]);
+ MY_ASSERT(PR_SUCCESS == rv);
+ }
+ PrintProgress(__LINE__);
+ did = PR_FALSE; should = PR_TRUE;
+
+} /* Thread */
+
+static PRIntn PR_CALLBACK Tpd(PRIntn argc, char **argv)
+{
+ void *pd;
+ PRStatus rv;
+ PRUintn keys;
+ PRThread *thread;
+ char *key_string[] = {
+ "Key #0", "Key #1", "Key #2", "Key #3",
+ "Bogus #5", "Bogus #6", "Bogus #7", "Bogus #8"
+ };
+
+ fout = PR_STDOUT;
+
+ did = should = PR_FALSE;
+ for (keys = 0; keys < 4; ++keys)
+ {
+ rv = PR_NewThreadPrivateIndex(&key[keys], Destructor);
+ MY_ASSERT(PR_SUCCESS == rv);
+ }
+ PrintProgress(__LINE__);
+
+ did = should = PR_FALSE;
+ for (keys = 0; keys < 8; ++keys)
+ {
+ pd = PR_GetThreadPrivate(key[keys]);
+ MY_ASSERT(NULL == pd);
+ }
+ PrintProgress(__LINE__);
+
+ did = should = PR_FALSE;
+ for (keys = 0; keys < 4; ++keys)
+ {
+ rv = PR_SetThreadPrivate(key[keys], key_string[keys]);
+ MY_ASSERT(PR_SUCCESS == rv);
+ }
+ PrintProgress(__LINE__);
+
+ for (keys = 4; keys < 8; ++keys) {
+ key[keys] = 4096; /* set to invalid value */
+ }
+ did = should = PR_FALSE;
+ for (keys = 4; keys < 8; ++keys)
+ {
+ rv = PR_SetThreadPrivate(key[keys], key_string[keys]);
+ MY_ASSERT(PR_FAILURE == rv);
+ }
+ PrintProgress(__LINE__);
+
+ did = PR_FALSE; should = PR_TRUE;
+ for (keys = 0; keys < 4; ++keys)
+ {
+ rv = PR_SetThreadPrivate(key[keys], key_string[keys]);
+ MY_ASSERT(PR_SUCCESS == rv);
+ }
+ PrintProgress(__LINE__);
+
+ did = PR_FALSE; should = PR_TRUE;
+ for (keys = 0; keys < 4; ++keys)
+ {
+ rv = PR_SetThreadPrivate(key[keys], NULL);
+ MY_ASSERT(PR_SUCCESS == rv);
+ }
+ PrintProgress(__LINE__);
+
+ did = should = PR_FALSE;
+ for (keys = 0; keys < 4; ++keys)
+ {
+ rv = PR_SetThreadPrivate(key[keys], NULL);
+ MY_ASSERT(PR_SUCCESS == rv);
+ }
+ PrintProgress(__LINE__);
+
+ did = should = PR_FALSE;
+ for (keys = 8; keys < 127; ++keys)
+ {
+ rv = PR_NewThreadPrivateIndex(&key[keys], Destructor);
+ MY_ASSERT(PR_SUCCESS == rv);
+ rv = PR_SetThreadPrivate(key[keys], "EXTENSION");
+ MY_ASSERT(PR_SUCCESS == rv);
+ }
+ PrintProgress(__LINE__);
+
+ did = PR_FALSE; should = PR_TRUE;
+ for (keys = 8; keys < 127; ++keys)
+ {
+ rv = PR_SetThreadPrivate(key[keys], NULL);
+ MY_ASSERT(PR_SUCCESS == rv);
+ }
+ PrintProgress(__LINE__);
+
+ did = should = PR_FALSE;
+ for (keys = 8; keys < 127; ++keys)
+ {
+ rv = PR_SetThreadPrivate(key[keys], NULL);
+ MY_ASSERT(PR_SUCCESS == rv);
+ }
+
+ thread = PR_CreateThread(
+ PR_USER_THREAD, Thread, NULL, PR_PRIORITY_NORMAL,
+ PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0);
+
+ (void)PR_JoinThread(thread);
+
+ PrintProgress(__LINE__);
+
+#if defined(WIN16)
+ printf(
+ "%s\n",((PR_TRUE == failed) ? "FAILED" : "PASSED"));
+#else
+ (void)PR_fprintf(
+ fout, "%s\n",((PR_TRUE == failed) ? "FAILED" : "PASSED"));
+#endif
+
+ return 0;
+
+} /* Tpd */
+
+int main(int argc, char **argv)
+{
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "dl:r:");
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 'd': /* debug mode */
+ debug = PR_TRUE;
+ break;
+ default:
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+ PR_STDIO_INIT();
+ return PR_Initialize(Tpd, argc, argv, 0);
+} /* main */
+
+/* tpd.c */
diff --git a/nsprpub/pr/tests/udpsrv.c b/nsprpub/pr/tests/udpsrv.c
new file mode 100644
index 0000000000..39a919c606
--- /dev/null
+++ b/nsprpub/pr/tests/udpsrv.c
@@ -0,0 +1,546 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*******************************************************************
+** udpsrc.c -- Test basic function of UDP server
+**
+** udpsrv operates on the same machine with program udpclt.
+** udpsrv is the server side of a udp sockets application.
+** udpclt is the client side of a udp sockets application.
+**
+** The test is designed to assist developers in porting/debugging
+** the UDP socket functions of NSPR.
+**
+** This test is not a stress test.
+**
+** main() starts two threads: UDP_Server() and UDP_Client();
+** main() uses PR_JoinThread() to wait for the threads to complete.
+**
+** UDP_Server() does repeated recvfrom()s from a socket.
+** He detects an EOF condition set by UDP_Client(). For each
+** packet received by UDP_Server(), he checks its content for
+** expected content, then sends the packet back to UDP_Client().
+**
+** UDP_Client() sends packets to UDP_Server() using sendto()
+** he recieves packets back from the server via recvfrom().
+** After he sends enough packets containing UDP_AMOUNT_TO_WRITE
+** bytes of data, he sends an EOF message.
+**
+** The test issues a pass/fail message at end.
+**
+** Notes:
+** The variable "_debug_on" can be set to 1 to cause diagnostic
+** messages related to client/server synchronization. Useful when
+** the test hangs.
+**
+** Error messages are written to stdout.
+**
+********************************************************************
+*/
+/* --- include files --- */
+#include "nspr.h"
+#include "prpriv.h"
+
+#include "plgetopt.h"
+#include "prttools.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#ifdef XP_PC
+#define mode_t int
+#endif
+
+#define UDP_BUF_SIZE 4096
+#define UDP_DGRAM_SIZE 128
+#define UDP_AMOUNT_TO_WRITE (PRInt32)((UDP_DGRAM_SIZE * 1000l) +1)
+#define NUM_UDP_CLIENTS 1
+#define NUM_UDP_DATAGRAMS_PER_CLIENT 5
+#define UDP_SERVER_PORT 9050
+#define UDP_CLIENT_PORT 9053
+#define MY_INADDR PR_INADDR_ANY
+#define PEER_INADDR PR_INADDR_LOOPBACK
+
+#define UDP_TIMEOUT 400000
+/* #define UDP_TIMEOUT PR_INTERVAL_NO_TIMEOUT */
+
+/* --- static data --- */
+static PRIntn _debug_on = 0;
+static PRBool passed = PR_TRUE;
+static PRUint32 cltBytesRead = 0;
+static PRUint32 srvBytesRead = 0;
+static PRFileDesc *output = NULL;
+
+/* --- static function declarations --- */
+#define DPRINTF(arg) if (_debug_on) PR_fprintf(output, arg)
+
+
+
+/*******************************************************************
+** ListNetAddr() -- Display the Net Address on stdout
+**
+** Description: displays the component parts of a PRNetAddr struct
+**
+** Arguments: address of PRNetAddr structure to display
+**
+** Returns: void
+**
+** Notes:
+**
+********************************************************************
+*/
+void ListNetAddr( char *msg, PRNetAddr *na )
+{
+ char mbuf[256];
+
+ sprintf( mbuf, "ListNetAddr: %s family: %d, port: %d, ip: %8.8X\n",
+ msg, na->inet.family, PR_ntohs( na->inet.port), PR_ntohl(na->inet.ip) );
+#if 0
+ DPRINTF( mbuf );
+#endif
+} /* --- end ListNetAddr() --- */
+
+/********************************************************************
+** UDP_Server() -- Test a UDP server application
+**
+** Description: The Server side of a UDP Client/Server application.
+**
+** Arguments: none
+**
+** Returns: void
+**
+** Notes:
+**
+**
+********************************************************************
+*/
+static void PR_CALLBACK UDP_Server( void *arg )
+{
+ static char svrBuf[UDP_BUF_SIZE];
+ PRFileDesc *svrSock;
+ PRInt32 rv;
+ PRNetAddr netaddr;
+ PRBool bound = PR_FALSE;
+ PRBool endOfInput = PR_FALSE;
+ PRInt32 numBytes = UDP_DGRAM_SIZE;
+
+ DPRINTF("udpsrv: UDP_Server(): starting\n" );
+
+ /* --- Create the socket --- */
+ DPRINTF("udpsrv: UDP_Server(): Creating UDP Socket\n" );
+ svrSock = PR_NewUDPSocket();
+ if ( svrSock == NULL )
+ {
+ passed = PR_FALSE;
+ if (debug_mode)
+ PR_fprintf(output,
+ "udpsrv: UDP_Server(): PR_NewUDPSocket() returned NULL\n" );
+ return;
+ }
+
+ /* --- Initialize the sockaddr_in structure --- */
+ memset( &netaddr, 0, sizeof( netaddr ));
+ netaddr.inet.family = PR_AF_INET;
+ netaddr.inet.port = PR_htons( UDP_SERVER_PORT );
+ netaddr.inet.ip = PR_htonl( MY_INADDR );
+
+ /* --- Bind the socket --- */
+ while ( !bound )
+ {
+ DPRINTF("udpsrv: UDP_Server(): Binding socket\n" );
+ rv = PR_Bind( svrSock, &netaddr );
+ if ( rv < 0 )
+ {
+ if ( PR_GetError() == PR_ADDRESS_IN_USE_ERROR )
+ {
+ if (debug_mode) PR_fprintf(output, "udpsrv: UDP_Server(): \
+ PR_Bind(): reports: PR_ADDRESS_IN_USE_ERROR\n");
+ PR_Sleep( PR_MillisecondsToInterval( 2000 ));
+ continue;
+ }
+ else
+ {
+ passed = PR_FALSE;
+ if (debug_mode) PR_fprintf(output, "udpsrv: UDP_Server(): \
+ PR_Bind(): failed: %ld with error: %ld\n",
+ rv, PR_GetError() );
+ PR_Close( svrSock );
+ return;
+ }
+ }
+ else {
+ bound = PR_TRUE;
+ }
+ }
+ ListNetAddr( "UDP_Server: after bind", &netaddr );
+
+ /* --- Recv the socket --- */
+ while( !endOfInput )
+ {
+ DPRINTF("udpsrv: UDP_Server(): RecvFrom() socket\n" );
+ rv = PR_RecvFrom( svrSock, svrBuf, numBytes, 0, &netaddr, UDP_TIMEOUT );
+ if ( rv == -1 )
+ {
+ passed = PR_FALSE;
+ if (debug_mode)
+ PR_fprintf(output,
+ "udpsrv: UDP_Server(): PR_RecvFrom(): failed with error: %ld\n",
+ PR_GetError() );
+ PR_Close( svrSock );
+ return;
+ }
+ ListNetAddr( "UDP_Server after RecvFrom", &netaddr );
+
+ srvBytesRead += rv;
+
+ if ( svrBuf[0] == 'E' )
+ {
+ DPRINTF("udpsrv: UDP_Server(): EOF on input detected\n" );
+ endOfInput = PR_TRUE;
+ }
+
+ /* --- Send the socket --- */
+ DPRINTF("udpsrv: UDP_Server(): SendTo(): socket\n" );
+ rv = PR_SendTo( svrSock, svrBuf, rv, 0, &netaddr, PR_INTERVAL_NO_TIMEOUT );
+ if ( rv == -1 )
+ {
+ passed = PR_FALSE;
+ if (debug_mode)
+ PR_fprintf(output,
+ "udpsrv: UDP_Server(): PR_SendTo(): failed with error: %ld\n",
+ PR_GetError() );
+ PR_Close( svrSock );
+ return;
+ }
+ ListNetAddr( "UDP_Server after SendTo", &netaddr );
+ }
+
+ /* --- Close the socket --- */
+ DPRINTF("udpsrv: UDP_Server(): Closing socket\n" );
+ rv = PR_Close( svrSock );
+ if ( rv != PR_SUCCESS )
+ {
+ passed = PR_FALSE;
+ if (debug_mode)
+ PR_fprintf(output,
+ "udpsrv: UDP_Server(): PR_Close(): failed to close socket\n" );
+ return;
+ }
+
+ DPRINTF("udpsrv: UDP_Server(): Normal end\n" );
+} /* --- end UDP_Server() --- */
+
+
+static char cltBuf[UDP_BUF_SIZE];
+static char cltBufin[UDP_BUF_SIZE];
+/********************************************************************
+** UDP_Client() -- Test a UDP client application
+**
+** Description:
+**
+** Arguments:
+**
+**
+** Returns:
+** 0 -- Successful execution
+** 1 -- Test failed.
+**
+** Notes:
+**
+**
+********************************************************************
+*/
+static void PR_CALLBACK UDP_Client( void *arg )
+{
+ PRFileDesc *cltSock;
+ PRInt32 rv;
+ PRBool bound = PR_FALSE;
+ PRNetAddr netaddr;
+ PRNetAddr netaddrx;
+ PRBool endOfInput = PR_FALSE;
+ PRInt32 numBytes = UDP_DGRAM_SIZE;
+ PRInt32 writeThisMany = UDP_AMOUNT_TO_WRITE;
+ int i;
+
+
+ DPRINTF("udpsrv: UDP_Client(): starting\n" );
+
+ /* --- Create the socket --- */
+ cltSock = PR_NewUDPSocket();
+ if ( cltSock == NULL )
+ {
+ passed = PR_FALSE;
+ if (debug_mode)
+ PR_fprintf(output,
+ "udpsrv: UDP_Client(): PR_NewUDPSocket() returned NULL\n" );
+ return;
+ }
+
+ /* --- Initialize the sockaddr_in structure --- */
+ memset( &netaddr, 0, sizeof( netaddr ));
+ netaddr.inet.family = PR_AF_INET;
+ netaddr.inet.ip = PR_htonl( MY_INADDR );
+ netaddr.inet.port = PR_htons( UDP_CLIENT_PORT );
+
+ /* --- Initialize the write buffer --- */
+ for ( i = 0; i < UDP_BUF_SIZE ; i++ ) {
+ cltBuf[i] = i;
+ }
+
+ /* --- Bind the socket --- */
+ while ( !bound )
+ {
+ DPRINTF("udpsrv: UDP_Client(): Binding socket\n" );
+ rv = PR_Bind( cltSock, &netaddr );
+ if ( rv < 0 )
+ {
+ if ( PR_GetError() == PR_ADDRESS_IN_USE_ERROR )
+ {
+ if (debug_mode)
+ PR_fprintf(output,
+ "udpsrv: UDP_Client(): PR_Bind(): reports: PR_ADDRESS_IN_USE_ERROR\n");
+ PR_Sleep( PR_MillisecondsToInterval( 2000 ));
+ continue;
+ }
+ else
+ {
+ passed = PR_FALSE;
+ if (debug_mode)
+ PR_fprintf(output,
+ "udpsrv: UDP_Client(): PR_Bind(): failed: %ld with error: %ld\n",
+ rv, PR_GetError() );
+ PR_Close( cltSock );
+ return;
+ }
+ }
+ else {
+ bound = PR_TRUE;
+ }
+ }
+ ListNetAddr( "UDP_Client after Bind", &netaddr );
+
+ /* --- Initialize the sockaddr_in structure --- */
+ memset( &netaddr, 0, sizeof( netaddr ));
+ netaddr.inet.family = PR_AF_INET;
+ netaddr.inet.ip = PR_htonl( PEER_INADDR );
+ netaddr.inet.port = PR_htons( UDP_SERVER_PORT );
+
+ /* --- send and receive packets until no more data left */
+ while( !endOfInput )
+ {
+ /*
+ ** Signal EOF in the data stream on the last packet
+ */
+ if ( writeThisMany <= UDP_DGRAM_SIZE )
+ {
+ DPRINTF("udpsrv: UDP_Client(): Send EOF packet\n" );
+ cltBuf[0] = 'E';
+ endOfInput = PR_TRUE;
+ }
+
+ /* --- SendTo the socket --- */
+ if ( writeThisMany > UDP_DGRAM_SIZE ) {
+ numBytes = UDP_DGRAM_SIZE;
+ }
+ else {
+ numBytes = writeThisMany;
+ }
+ writeThisMany -= numBytes;
+ {
+ char mbuf[256];
+ sprintf( mbuf, "udpsrv: UDP_Client(): write_this_many: %d, numbytes: %d\n",
+ writeThisMany, numBytes );
+ DPRINTF( mbuf );
+ }
+
+ DPRINTF("udpsrv: UDP_Client(): SendTo(): socket\n" );
+ rv = PR_SendTo( cltSock, cltBuf, numBytes, 0, &netaddr, UDP_TIMEOUT );
+ if ( rv == -1 )
+ {
+ passed = PR_FALSE;
+ if (debug_mode)
+ PR_fprintf(output,
+ "udpsrv: UDP_Client(): PR_SendTo(): failed with error: %ld\n",
+ PR_GetError() );
+ PR_Close( cltSock );
+ return;
+ }
+ ListNetAddr( "UDP_Client after SendTo", &netaddr );
+
+ /* --- RecvFrom the socket --- */
+ memset( cltBufin, 0, UDP_BUF_SIZE );
+ DPRINTF("udpsrv: UDP_Client(): RecvFrom(): socket\n" );
+ rv = PR_RecvFrom( cltSock, cltBufin, numBytes, 0, &netaddrx, UDP_TIMEOUT );
+ if ( rv == -1 )
+ {
+ passed = PR_FALSE;
+ if (debug_mode) PR_fprintf(output,
+ "udpsrv: UDP_Client(): PR_RecvFrom(): failed with error: %ld\n",
+ PR_GetError() );
+ PR_Close( cltSock );
+ return;
+ }
+ ListNetAddr( "UDP_Client after RecvFrom()", &netaddr );
+ cltBytesRead += rv;
+
+ /* --- verify buffer --- */
+ for ( i = 0; i < rv ; i++ )
+ {
+ if ( cltBufin[i] != i )
+ {
+ /* --- special case, end of input --- */
+ if ( endOfInput && i == 0 && cltBufin[0] == 'E' ) {
+ continue;
+ }
+ passed = PR_FALSE;
+ if (debug_mode) PR_fprintf(output,
+ "udpsrv: UDP_Client(): return data mismatch\n" );
+ PR_Close( cltSock );
+ return;
+ }
+ }
+ if (debug_mode) {
+ PR_fprintf(output, ".");
+ }
+ }
+
+ /* --- Close the socket --- */
+ DPRINTF("udpsrv: UDP_Server(): Closing socket\n" );
+ rv = PR_Close( cltSock );
+ if ( rv != PR_SUCCESS )
+ {
+ passed = PR_FALSE;
+ if (debug_mode) PR_fprintf(output,
+ "udpsrv: UDP_Client(): PR_Close(): failed to close socket\n" );
+ return;
+ }
+ DPRINTF("udpsrv: UDP_Client(): ending\n" );
+} /* --- end UDP_Client() --- */
+
+/********************************************************************
+** main() -- udpsrv
+**
+** arguments:
+**
+** Returns:
+** 0 -- Successful execution
+** 1 -- Test failed.
+**
+** Description:
+**
+** Standard test case setup.
+**
+** Calls the function UDP_Server()
+**
+********************************************************************
+*/
+
+int main(int argc, char **argv)
+{
+ PRThread *srv, *clt;
+ /* The command line argument: -d is used to determine if the test is being run
+ in debug mode. The regress tool requires only one line output:PASS or FAIL.
+ All of the printfs associated with this test has been handled with a if (debug_mode)
+ test.
+ Usage: test_name -d -v
+ */
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "dv");
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 'd': /* debug mode */
+ debug_mode = 1;
+ break;
+ case 'v': /* verbose mode */
+ _debug_on = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
+ PR_STDIO_INIT();
+ output = PR_STDERR;
+
+ PR_SetConcurrency(4);
+
+ /*
+ ** Create the Server thread
+ */
+ DPRINTF( "udpsrv: Creating Server Thread\n" );
+ srv = PR_CreateThread( PR_USER_THREAD,
+ UDP_Server,
+ (void *) 0,
+ PR_PRIORITY_LOW,
+ PR_LOCAL_THREAD,
+ PR_JOINABLE_THREAD,
+ 0 );
+ if ( srv == NULL )
+ {
+ if (debug_mode) {
+ PR_fprintf(output, "udpsrv: Cannot create server thread\n" );
+ }
+ passed = PR_FALSE;
+ }
+
+ /*
+ ** Give the Server time to Start
+ */
+ DPRINTF( "udpsrv: Pausing to allow Server to start\n" );
+ PR_Sleep( PR_MillisecondsToInterval(200) );
+
+ /*
+ ** Create the Client thread
+ */
+ DPRINTF( "udpsrv: Creating Client Thread\n" );
+ clt = PR_CreateThread( PR_USER_THREAD,
+ UDP_Client,
+ (void *) 0,
+ PR_PRIORITY_LOW,
+ PR_LOCAL_THREAD,
+ PR_JOINABLE_THREAD,
+ 0 );
+ if ( clt == NULL )
+ {
+ if (debug_mode) {
+ PR_fprintf(output, "udpsrv: Cannot create server thread\n" );
+ }
+ passed = PR_FALSE;
+ }
+
+ /*
+ **
+ */
+ DPRINTF("udpsrv: Waiting to join Server & Client Threads\n" );
+ PR_JoinThread( srv );
+ PR_JoinThread( clt );
+
+ /*
+ ** Evaluate test results
+ */
+ if (debug_mode) PR_fprintf(output, "\n\nudpsrv: main(): cltBytesRead(%ld), \
+ srvBytesRead(%ld), expected(%ld)\n",
+ cltBytesRead, srvBytesRead, UDP_AMOUNT_TO_WRITE );
+ if ( cltBytesRead != srvBytesRead || cltBytesRead != UDP_AMOUNT_TO_WRITE )
+ {
+ passed = PR_FALSE;
+ }
+ PR_Cleanup();
+ if ( passed ) {
+ return 0;
+ }
+ else {
+ return 1;
+ }
+} /* --- end main() --- */
diff --git a/nsprpub/pr/tests/ut_ttools.h b/nsprpub/pr/tests/ut_ttools.h
new file mode 100644
index 0000000000..e3cac5daa9
--- /dev/null
+++ b/nsprpub/pr/tests/ut_ttools.h
@@ -0,0 +1,11 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* Used in Regress Tool */
+#define NOSTATUS 2
+#define PASS 1
+#define FAIL 0
+
+PRIntn debug_mode=0;
diff --git a/nsprpub/pr/tests/vercheck.c b/nsprpub/pr/tests/vercheck.c
new file mode 100644
index 0000000000..7383960300
--- /dev/null
+++ b/nsprpub/pr/tests/vercheck.c
@@ -0,0 +1,92 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * File: vercheck.c
+ *
+ * Description:
+ * This test tests the PR_VersionCheck() function. The
+ * compatible_version and incompatible_version arrays
+ * need to be updated for each patch or release.
+ *
+ * Tested areas: library version compatibility check.
+ */
+
+#include "prinit.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+/*
+ * This release (4.10.10) is backward compatible with the
+ * 4.0.x, 4.1.x, 4.2.x, 4.3.x, 4.4.x, 4.5.x, 4.6.x, 4.7.x,
+ * 4.8.x, 4.9.x, 4.10.x and 4.11.X releases.
+ * It, of course, is compatible with itself.
+ */
+static char *compatible_version[] = {
+ "4.0", "4.0.1", "4.1", "4.1.1", "4.1.2", "4.1.3",
+ "4.2", "4.2.1", "4.2.2", "4.3", "4.4", "4.4.1",
+ "4.5", "4.5.1",
+ "4.6", "4.6.1", "4.6.2", "4.6.3", "4.6.4", "4.6.5",
+ "4.6.6", "4.6.7", "4.6.8",
+ "4.7", "4.7.1", "4.7.2", "4.7.3", "4.7.4", "4.7.5",
+ "4.7.6",
+ "4.8", "4.8.1", "4.8.2", "4.8.3", "4.8.4", "4.8.5",
+ "4.8.6", "4.8.7", "4.8.8", "4.8.9",
+ "4.9", "4.9.1", "4.9.2", "4.9.3", "4.9.4", "4.9.5",
+ "4.9.6",
+ "4.10", "4.10.1", "4.10.2", "4.10.3", "4.10.4",
+ "4.10.5", "4.10.6", "4.10.7", "4.10.8", "4.10.9",
+ "4.10.10", "4.11", "4.12", "4.13", "4.14", "4.15",
+ "4.16", "4.17", "4.18", "4.19", "4.20", "4.21", "4.22",
+ "4.23", "4.24", "4.25", "4,26", "4.27", "4.28",
+ PR_VERSION
+};
+
+/*
+ * This release is not backward compatible with the old
+ * NSPR 2.1 and 3.x releases.
+ *
+ * Any release is incompatible with future releases and
+ * patches.
+ */
+static char *incompatible_version[] = {
+ "2.1 19980529",
+ "3.0", "3.0.1",
+ "3.1", "3.1.1", "3.1.2", "3.1.3",
+ "3.5", "3.5.1",
+ "4.29.1",
+ "4.30", "4.30.1",
+ "10.0", "11.1", "12.14.20"
+};
+
+int main(int argc, char **argv)
+{
+ int idx;
+ int num_compatible = sizeof(compatible_version) / sizeof(char *);
+ int num_incompatible = sizeof(incompatible_version) / sizeof(char *);
+
+ printf("NSPR release %s:\n", PR_VERSION);
+ for (idx = 0; idx < num_compatible; idx++) {
+ if (PR_VersionCheck(compatible_version[idx]) == PR_FALSE) {
+ fprintf(stderr, "Should be compatible with version %s\n",
+ compatible_version[idx]);
+ exit(1);
+ }
+ printf("Compatible with version %s\n", compatible_version[idx]);
+ }
+
+ for (idx = 0; idx < num_incompatible; idx++) {
+ if (PR_VersionCheck(incompatible_version[idx]) == PR_TRUE) {
+ fprintf(stderr, "Should be incompatible with version %s\n",
+ incompatible_version[idx]);
+ exit(1);
+ }
+ printf("Incompatible with version %s\n", incompatible_version[idx]);
+ }
+
+ printf("PASS\n");
+ return 0;
+}
diff --git a/nsprpub/pr/tests/version.c b/nsprpub/pr/tests/version.c
new file mode 100644
index 0000000000..49e8a05d78
--- /dev/null
+++ b/nsprpub/pr/tests/version.c
@@ -0,0 +1,94 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "prio.h"
+#include "prprf.h"
+#include "prlink.h"
+#include "prvrsion.h"
+
+#include "plerror.h"
+#include "plgetopt.h"
+
+PR_IMPORT(const PRVersionDescription *) libVersionPoint(void);
+
+int main(int argc, char **argv)
+{
+ PRIntn rv = 1;
+ PLOptStatus os;
+ PRIntn verbosity = 0;
+ PRLibrary *runtime = NULL;
+ const char *library_name = NULL;
+ const PRVersionDescription *version_info;
+ char buffer[100];
+ PRExplodedTime exploded;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "d");
+
+ PRFileDesc *err = PR_GetSpecialFD(PR_StandardError);
+
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 0: /* fully qualified library name */
+ library_name = opt->value;
+ break;
+ case 'd': /* verbodity */
+ verbosity += 1;
+ break;
+ default:
+ PR_fprintf(err, "Usage: version [-d] {fully qualified library name}\n");
+ return 2; /* but not a lot else */
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ if (NULL != library_name)
+ {
+ runtime = PR_LoadLibrary(library_name);
+ if (NULL == runtime) {
+ PL_FPrintError(err, "PR_LoadLibrary");
+ return 3;
+ } else {
+ versionEntryPointType versionPoint = (versionEntryPointType)
+ PR_FindSymbol(runtime, "libVersionPoint");
+ if (NULL == versionPoint) {
+ PL_FPrintError(err, "PR_FindSymbol");
+ return 4;
+ }
+ version_info = versionPoint();
+ }
+ } else {
+ version_info = libVersionPoint(); /* NSPR's version info */
+ }
+
+ (void)PR_fprintf(err, "Runtime library version information\n");
+ PR_ExplodeTime(
+ version_info->buildTime, PR_GMTParameters, &exploded);
+ (void)PR_FormatTime(
+ buffer, sizeof(buffer), "%d %b %Y %H:%M:%S", &exploded);
+ (void)PR_fprintf(err, " Build time: %s GMT\n", buffer);
+ (void)PR_fprintf(
+ err, " Build time: %s\n", version_info->buildTimeString);
+ (void)PR_fprintf(
+ err, " %s V%u.%u.%u (%s%s%s)\n",
+ version_info->description,
+ version_info->vMajor,
+ version_info->vMinor,
+ version_info->vPatch,
+ (version_info->beta ? " beta " : ""),
+ (version_info->debug ? " debug " : ""),
+ (version_info->special ? " special" : ""));
+ (void)PR_fprintf(err, " filename: %s\n", version_info->filename);
+ (void)PR_fprintf(err, " security: %s\n", version_info->security);
+ (void)PR_fprintf(err, " copyright: %s\n", version_info->copyright);
+ (void)PR_fprintf(err, " comment: %s\n", version_info->comment);
+ rv = 0;
+ return rv;
+}
+
+/* version.c */
diff --git a/nsprpub/pr/tests/writev.c b/nsprpub/pr/tests/writev.c
new file mode 100644
index 0000000000..f72f00fb44
--- /dev/null
+++ b/nsprpub/pr/tests/writev.c
@@ -0,0 +1,225 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nspr.h"
+
+#include "plgetopt.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+
+#ifndef IOV_MAX
+#define IOV_MAX 16
+#endif
+
+#ifdef DEBUG
+#define PORT_INC_DO +100
+#else
+#define PORT_INC_DO
+#endif
+#ifdef IS_64
+#define PORT_INC_3264 +200
+#else
+#define PORT_INC_3264
+#endif
+
+#define BASE_PORT 9867 PORT_INC_DO PORT_INC_3264
+
+int PR_CALLBACK Writev(int argc, char **argv)
+{
+
+ PRStatus rv;
+ PRNetAddr serverAddr;
+ PRFileDesc *clientSock, *debug = NULL;
+
+ char *buffer = NULL;
+ PRIOVec *iov = NULL;
+ PRBool passed = PR_TRUE;
+ PRIntervalTime timein, elapsed, timeout;
+ PRIntervalTime tmo_min = 0x7fffffff, tmo_max = 0, tmo_elapsed = 0;
+ PRInt32 tmo_counted = 0, iov_index, loop, bytes, number_fragments;
+ PRInt32 message_length = 100, fragment_length = 100, messages = 100;
+ struct Descriptor {
+ PRInt32 length;
+ PRUint32 checksum;
+ } descriptor;
+
+ /*
+ * USAGE
+ * -h dns name of host serving the connection (default = self)
+ * -m number of messages to send (default = 100)
+ * -s size of each message (default = 100)
+ * -f size of each message fragment (default = 100)
+ */
+
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "dh:m:s:f:");
+
+ PR_STDIO_INIT();
+ rv = PR_InitializeNetAddr(PR_IpAddrLoopback, BASE_PORT, &serverAddr);
+ PR_ASSERT(PR_SUCCESS == rv);
+
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 'h': /* the remote host */
+ {
+ PRIntn es = 0;
+ PRHostEnt host;
+ char buffer[1024];
+ (void)PR_GetHostByName(opt->value, buffer, sizeof(buffer), &host);
+ es = PR_EnumerateHostEnt(es, &host, BASE_PORT, &serverAddr);
+ PR_ASSERT(es > 0);
+ }
+ break;
+ case 'd': /* debug mode */
+ debug = PR_GetSpecialFD(PR_StandardError);
+ break;
+ case 'm': /* number of messages to send */
+ messages = atoi(opt->value);
+ break;
+ case 's': /* total size of each message */
+ message_length = atoi(opt->value);
+ break;
+ case 'f': /* size of each message fragment */
+ fragment_length = atoi(opt->value);
+ break;
+ default:
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ buffer = (char*)malloc(message_length);
+
+ number_fragments = (message_length + fragment_length - 1) / fragment_length + 1;
+ while (IOV_MAX < number_fragments)
+ {
+ fragment_length = message_length / (IOV_MAX - 2);
+ number_fragments = (message_length + fragment_length - 1) /
+ fragment_length + 1;
+ if (NULL != debug) PR_fprintf(debug,
+ "Too many fragments - reset fragment length to %ld\n", fragment_length);
+ }
+ iov = (PRIOVec*)malloc(number_fragments * sizeof(PRIOVec));
+
+ iov[0].iov_base = (char*)&descriptor;
+ iov[0].iov_len = sizeof(descriptor);
+ for (iov_index = 1; iov_index < number_fragments; ++iov_index)
+ {
+ iov[iov_index].iov_base = buffer + (iov_index - 1) * fragment_length;
+ iov[iov_index].iov_len = fragment_length;
+ }
+
+ for (bytes = 0; bytes < message_length; ++bytes) {
+ buffer[bytes] = (char)bytes;
+ }
+
+ timeout = PR_SecondsToInterval(1);
+
+ for (loop = 0; loop < messages; ++loop)
+ {
+ if (NULL != debug) {
+ PR_fprintf(debug, "[%d]socket ... ", loop);
+ }
+ clientSock = PR_NewTCPSocket();
+ if (clientSock)
+ {
+ timein = PR_IntervalNow();
+ if (NULL != debug) {
+ PR_fprintf(debug, "connecting ... ");
+ }
+ rv = PR_Connect(clientSock, &serverAddr, timeout);
+ if (PR_SUCCESS == rv)
+ {
+ descriptor.checksum = 0;
+ descriptor.length = (loop < (messages - 1)) ? message_length : 0;
+ if (0 == descriptor.length) {
+ number_fragments = 1;
+ }
+ else
+ for (iov_index = 0; iov_index < descriptor.length; ++iov_index)
+ {
+ PRUint32 overflow = descriptor.checksum & 0x80000000;
+ descriptor.checksum = (descriptor.checksum << 1);
+ if (0x00000000 != overflow) {
+ descriptor.checksum += 1;
+ }
+ descriptor.checksum += buffer[iov_index];
+ }
+ if (NULL != debug) PR_fprintf(
+ debug, "sending %d bytes ... ", descriptor.length);
+
+ /* then, at the last moment ... */
+ descriptor.length = PR_ntohl(descriptor.length);
+ descriptor.checksum = PR_ntohl(descriptor.checksum);
+
+ bytes = PR_Writev(clientSock, iov, number_fragments, timeout);
+ if (NULL != debug) {
+ PR_fprintf(debug, "closing ... ");
+ }
+ rv = PR_Shutdown(clientSock, PR_SHUTDOWN_BOTH);
+ rv = PR_Close(clientSock);
+ if (NULL != debug) PR_fprintf(
+ debug, "%s\n", ((PR_SUCCESS == rv) ? "good" : "bad"));
+ elapsed = PR_IntervalNow() - timein;
+ if (elapsed < tmo_min) {
+ tmo_min = elapsed;
+ }
+ else if (elapsed > tmo_max) {
+ tmo_max = elapsed;
+ }
+ tmo_elapsed += elapsed;
+ tmo_counted += 1;
+ }
+ else
+ {
+ if (NULL != debug) PR_fprintf(
+ debug, "failed - retrying (%d, %d)\n",
+ PR_GetError(), PR_GetOSError());
+ PR_Close(clientSock);
+ }
+ }
+ else if (NULL != debug)
+ {
+ PR_fprintf(debug, "unable to create client socket\n");
+ passed = PR_FALSE;
+ }
+ }
+ if (NULL != debug) {
+ if (0 == tmo_counted) {
+ PR_fprintf(debug, "No connection made\n");
+ } else {
+ PR_fprintf(
+ debug, "\nTimings: %d [%d] %d (microseconds)\n",
+ PR_IntervalToMicroseconds(tmo_min),
+ PR_IntervalToMicroseconds(tmo_elapsed / tmo_counted),
+ PR_IntervalToMicroseconds(tmo_max));
+ }
+ }
+
+ PR_DELETE(buffer);
+ PR_DELETE(iov);
+
+ PR_fprintf(
+ PR_GetSpecialFD(PR_StandardError),
+ "%s\n", (passed) ? "PASSED" : "FAILED");
+ return (passed) ? 0 : 1;
+}
+
+int main(int argc, char **argv)
+{
+ return (PR_VersionCheck(PR_VERSION)) ?
+ PR_Initialize(Writev, argc, argv, 4) : -1;
+} /* main */
+
+/* writev.c */
+
+
diff --git a/nsprpub/pr/tests/xnotify.c b/nsprpub/pr/tests/xnotify.c
new file mode 100644
index 0000000000..7e6f0e2936
--- /dev/null
+++ b/nsprpub/pr/tests/xnotify.c
@@ -0,0 +1,429 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "plerror.h"
+#include "plgetopt.h"
+
+#include "prinit.h"
+#include "prprf.h"
+#include "prio.h"
+#include "prcvar.h"
+#include "prmon.h"
+#include "prcmon.h"
+#include "prlock.h"
+#include "prerror.h"
+#include "prinit.h"
+#include "prinrval.h"
+#include "prthread.h"
+
+static PRLock *ml = NULL;
+static PRIntervalTime base;
+static PRFileDesc *err = NULL;
+
+typedef struct CMonShared
+{
+ PRInt32 o1, o2;
+} CMonShared;
+
+typedef struct MonShared
+{
+ PRMonitor *o1, *o2;
+} MonShared;
+
+typedef struct LockShared
+{
+ PRLock *o1, *o2;
+ PRCondVar *cv1, *cv2;
+} LockShared;
+
+static void LogNow(const char *msg, PRStatus rv)
+{
+ PRIntervalTime now = PR_IntervalNow();
+ PR_Lock(ml);
+ PR_fprintf(err, "%6ld: %s", (now - base), msg);
+ if (PR_FAILURE == rv) {
+ PL_FPrintError(err, " ");
+ }
+ else {
+ PR_fprintf(err, "\n");
+ }
+ PR_Unlock(ml);
+} /* LogNow */
+
+static void Help(void)
+{
+ PR_fprintf(err, "Usage: [-[d][l][m][c]] [-h]\n");
+ PR_fprintf(err, "\t-d debug mode (default: FALSE)\n");
+ PR_fprintf(err, "\t-l test with locks (default: FALSE)\n");
+ PR_fprintf(err, "\t-m tests with monitors (default: FALSE)\n");
+ PR_fprintf(err, "\t-c tests with cmonitors (default: FALSE)\n");
+ PR_fprintf(err, "\t-h help\n");
+} /* Help */
+
+static void PR_CALLBACK T2CMon(void *arg)
+{
+ PRStatus rv;
+ CMonShared *shared = (CMonShared*)arg;
+
+ PR_CEnterMonitor(&shared->o1);
+ LogNow("T2 waiting 5 seconds on o1", PR_SUCCESS);
+ rv = PR_CWait(&shared->o1, PR_SecondsToInterval(5));
+ if (PR_SUCCESS == rv) {
+ LogNow("T2 resuming on o1", rv);
+ }
+ else {
+ LogNow("T2 wait failed on o1", rv);
+ }
+
+ rv = PR_CNotify(&shared->o1);
+ if (PR_SUCCESS == rv) {
+ LogNow("T2 notified o1", rv);
+ }
+ else {
+ LogNow("T2 notify on o1 failed", rv);
+ }
+
+ PR_CExitMonitor(&shared->o1);
+} /* T2CMon */
+
+static void PR_CALLBACK T3CMon(void *arg)
+{
+ PRStatus rv;
+ CMonShared *shared = (CMonShared*)arg;
+
+ PR_CEnterMonitor(&shared->o2);
+ LogNow("T3 waiting 5 seconds on o2", PR_SUCCESS);
+ rv = PR_CWait(&shared->o2, PR_SecondsToInterval(5));
+ if (PR_SUCCESS == rv) {
+ LogNow("T3 resuming on o2", rv);
+ }
+ else {
+ LogNow("T3 wait failed on o2", rv);
+ }
+ rv = PR_CNotify(&shared->o2);
+ LogNow("T3 notify on o2", rv);
+ PR_CExitMonitor(&shared->o2);
+
+} /* T3CMon */
+
+static CMonShared sharedCM;
+
+static void T1CMon(void)
+{
+ PRStatus rv;
+ PRThread *t2, *t3;
+
+ PR_fprintf(err, "\n**********************************\n");
+ PR_fprintf(err, " CACHED MONITORS\n");
+ PR_fprintf(err, "**********************************\n");
+
+ base = PR_IntervalNow();
+
+ PR_CEnterMonitor(&sharedCM.o1);
+ LogNow("T1 waiting 3 seconds on o1", PR_SUCCESS);
+ rv = PR_CWait(&sharedCM.o1, PR_SecondsToInterval(3));
+ if (PR_SUCCESS == rv) {
+ LogNow("T1 resuming on o1", rv);
+ }
+ else {
+ LogNow("T1 wait on o1 failed", rv);
+ }
+ PR_CExitMonitor(&sharedCM.o1);
+
+ LogNow("T1 creating T2", PR_SUCCESS);
+ t2 = PR_CreateThread(
+ PR_USER_THREAD, T2CMon, &sharedCM, PR_PRIORITY_NORMAL,
+ PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0);
+
+ LogNow("T1 creating T3", PR_SUCCESS);
+ t3 = PR_CreateThread(
+ PR_USER_THREAD, T3CMon, &sharedCM, PR_PRIORITY_NORMAL,
+ PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0);
+
+ PR_CEnterMonitor(&sharedCM.o2);
+ LogNow("T1 waiting forever on o2", PR_SUCCESS);
+ rv = PR_CWait(&sharedCM.o2, PR_INTERVAL_NO_TIMEOUT);
+ if (PR_SUCCESS == rv) {
+ LogNow("T1 resuming on o2", rv);
+ }
+ else {
+ LogNow("T1 wait on o2 failed", rv);
+ }
+ PR_CExitMonitor(&sharedCM.o2);
+
+ (void)PR_JoinThread(t2);
+ (void)PR_JoinThread(t3);
+
+} /* T1CMon */
+
+static void PR_CALLBACK T2Mon(void *arg)
+{
+ PRStatus rv;
+ MonShared *shared = (MonShared*)arg;
+
+ PR_EnterMonitor(shared->o1);
+ LogNow("T2 waiting 5 seconds on o1", PR_SUCCESS);
+ rv = PR_Wait(shared->o1, PR_SecondsToInterval(5));
+ if (PR_SUCCESS == rv) {
+ LogNow("T2 resuming on o1", rv);
+ }
+ else {
+ LogNow("T2 wait failed on o1", rv);
+ }
+
+ rv = PR_Notify(shared->o1);
+ if (PR_SUCCESS == rv) {
+ LogNow("T2 notified o1", rv);
+ }
+ else {
+ LogNow("T2 notify on o1 failed", rv);
+ }
+
+ PR_ExitMonitor(shared->o1);
+} /* T2Mon */
+
+static void PR_CALLBACK T3Mon(void *arg)
+{
+ PRStatus rv;
+ MonShared *shared = (MonShared*)arg;
+
+ PR_EnterMonitor(shared->o2);
+ LogNow("T3 waiting 5 seconds on o2", PR_SUCCESS);
+ rv = PR_Wait(shared->o2, PR_SecondsToInterval(5));
+ if (PR_SUCCESS == rv) {
+ LogNow("T3 resuming on o2", rv);
+ }
+ else {
+ LogNow("T3 wait failed on o2", rv);
+ }
+ rv = PR_Notify(shared->o2);
+ LogNow("T3 notify on o2", rv);
+ PR_ExitMonitor(shared->o2);
+
+} /* T3Mon */
+
+static MonShared sharedM;
+static void T1Mon(void)
+{
+ PRStatus rv;
+ PRThread *t2, *t3;
+
+ PR_fprintf(err, "\n**********************************\n");
+ PR_fprintf(err, " MONITORS\n");
+ PR_fprintf(err, "**********************************\n");
+
+ sharedM.o1 = PR_NewMonitor();
+ sharedM.o2 = PR_NewMonitor();
+
+ base = PR_IntervalNow();
+
+ PR_EnterMonitor(sharedM.o1);
+ LogNow("T1 waiting 3 seconds on o1", PR_SUCCESS);
+ rv = PR_Wait(sharedM.o1, PR_SecondsToInterval(3));
+ if (PR_SUCCESS == rv) {
+ LogNow("T1 resuming on o1", rv);
+ }
+ else {
+ LogNow("T1 wait on o1 failed", rv);
+ }
+ PR_ExitMonitor(sharedM.o1);
+
+ LogNow("T1 creating T2", PR_SUCCESS);
+ t2 = PR_CreateThread(
+ PR_USER_THREAD, T2Mon, &sharedM, PR_PRIORITY_NORMAL,
+ PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0);
+
+ LogNow("T1 creating T3", PR_SUCCESS);
+ t3 = PR_CreateThread(
+ PR_USER_THREAD, T3Mon, &sharedM, PR_PRIORITY_NORMAL,
+ PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0);
+
+ PR_EnterMonitor(sharedM.o2);
+ LogNow("T1 waiting forever on o2", PR_SUCCESS);
+ rv = PR_Wait(sharedM.o2, PR_INTERVAL_NO_TIMEOUT);
+ if (PR_SUCCESS == rv) {
+ LogNow("T1 resuming on o2", rv);
+ }
+ else {
+ LogNow("T1 wait on o2 failed", rv);
+ }
+ PR_ExitMonitor(sharedM.o2);
+
+ (void)PR_JoinThread(t2);
+ (void)PR_JoinThread(t3);
+
+ PR_DestroyMonitor(sharedM.o1);
+ PR_DestroyMonitor(sharedM.o2);
+
+} /* T1Mon */
+
+static void PR_CALLBACK T2Lock(void *arg)
+{
+ PRStatus rv;
+ LockShared *shared = (LockShared*)arg;
+
+ PR_Lock(shared->o1);
+ LogNow("T2 waiting 5 seconds on o1", PR_SUCCESS);
+ rv = PR_WaitCondVar(shared->cv1, PR_SecondsToInterval(5));
+ if (PR_SUCCESS == rv) {
+ LogNow("T2 resuming on o1", rv);
+ }
+ else {
+ LogNow("T2 wait failed on o1", rv);
+ }
+
+ rv = PR_NotifyCondVar(shared->cv1);
+ if (PR_SUCCESS == rv) {
+ LogNow("T2 notified o1", rv);
+ }
+ else {
+ LogNow("T2 notify on o1 failed", rv);
+ }
+
+ PR_Unlock(shared->o1);
+} /* T2Lock */
+
+static void PR_CALLBACK T3Lock(void *arg)
+{
+ PRStatus rv;
+ LockShared *shared = (LockShared*)arg;
+
+ PR_Lock(shared->o2);
+ LogNow("T3 waiting 5 seconds on o2", PR_SUCCESS);
+ rv = PR_WaitCondVar(shared->cv2, PR_SecondsToInterval(5));
+ if (PR_SUCCESS == rv) {
+ LogNow("T3 resuming on o2", rv);
+ }
+ else {
+ LogNow("T3 wait failed on o2", rv);
+ }
+ rv = PR_NotifyCondVar(shared->cv2);
+ LogNow("T3 notify on o2", rv);
+ PR_Unlock(shared->o2);
+
+} /* T3Lock */
+
+/*
+** Make shared' a static variable for Win16
+*/
+static LockShared sharedL;
+
+static void T1Lock(void)
+{
+ PRStatus rv;
+ PRThread *t2, *t3;
+ sharedL.o1 = PR_NewLock();
+ sharedL.o2 = PR_NewLock();
+ sharedL.cv1 = PR_NewCondVar(sharedL.o1);
+ sharedL.cv2 = PR_NewCondVar(sharedL.o2);
+
+ PR_fprintf(err, "\n**********************************\n");
+ PR_fprintf(err, " LOCKS\n");
+ PR_fprintf(err, "**********************************\n");
+
+ base = PR_IntervalNow();
+
+ PR_Lock(sharedL.o1);
+ LogNow("T1 waiting 3 seconds on o1", PR_SUCCESS);
+ rv = PR_WaitCondVar(sharedL.cv1, PR_SecondsToInterval(3));
+ if (PR_SUCCESS == rv) {
+ LogNow("T1 resuming on o1", rv);
+ }
+ else {
+ LogNow("T1 wait on o1 failed", rv);
+ }
+ PR_Unlock(sharedL.o1);
+
+ LogNow("T1 creating T2", PR_SUCCESS);
+ t2 = PR_CreateThread(
+ PR_USER_THREAD, T2Lock, &sharedL, PR_PRIORITY_NORMAL,
+ PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0);
+
+ LogNow("T1 creating T3", PR_SUCCESS);
+ t3 = PR_CreateThread(
+ PR_USER_THREAD, T3Lock, &sharedL, PR_PRIORITY_NORMAL,
+ PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0);
+
+ PR_Lock(sharedL.o2);
+ LogNow("T1 waiting forever on o2", PR_SUCCESS);
+ rv = PR_WaitCondVar(sharedL.cv2, PR_INTERVAL_NO_TIMEOUT);
+ if (PR_SUCCESS == rv) {
+ LogNow("T1 resuming on o2", rv);
+ }
+ else {
+ LogNow("T1 wait on o2 failed", rv);
+ }
+ PR_Unlock(sharedL.o2);
+
+ (void)PR_JoinThread(t2);
+ (void)PR_JoinThread(t3);
+
+ PR_DestroyLock(sharedL.o1);
+ PR_DestroyLock(sharedL.o2);
+ PR_DestroyCondVar(sharedL.cv1);
+ PR_DestroyCondVar(sharedL.cv2);
+} /* T1Lock */
+
+static PRIntn PR_CALLBACK RealMain( PRIntn argc, char **argv )
+{
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "dhlmc");
+ PRBool locks = PR_FALSE, monitors = PR_FALSE, cmonitors = PR_FALSE;
+
+ err = PR_GetSpecialFD(PR_StandardError);
+
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 'd': /* debug mode (noop) */
+ break;
+ case 'l': /* locks */
+ locks = PR_TRUE;
+ break;
+ case 'm': /* monitors */
+ monitors = PR_TRUE;
+ break;
+ case 'c': /* cached monitors */
+ cmonitors = PR_TRUE;
+ break;
+ case 'h': /* needs guidance */
+ default:
+ Help();
+ return 2;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ ml = PR_NewLock();
+ if (locks) {
+ T1Lock();
+ }
+ if (monitors) {
+ T1Mon();
+ }
+ if (cmonitors) {
+ T1CMon();
+ }
+
+ PR_DestroyLock(ml);
+
+ PR_fprintf(err, "Done!\n");
+ return 0;
+} /* main */
+
+
+int main(int argc, char **argv)
+{
+ PRIntn rv;
+
+ PR_STDIO_INIT();
+ rv = PR_Initialize(RealMain, argc, argv, 0);
+ return rv;
+} /* main */
+/* xnotify.c */
diff --git a/nsprpub/pr/tests/y2k.c b/nsprpub/pr/tests/y2k.c
new file mode 100644
index 0000000000..31b35e7e88
--- /dev/null
+++ b/nsprpub/pr/tests/y2k.c
@@ -0,0 +1,799 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * file: y2k.c
+ * description: Test for y2k compliance for NSPR.
+ *
+ * Sep 1999. lth. Added "Sun" specified dates to the test data.
+ */
+/***********************************************************************
+** Includes
+***********************************************************************/
+/* Used to get the command line option */
+#include "plgetopt.h"
+
+#include "prinit.h"
+#include "prtime.h"
+#include "prprf.h"
+#include "prlog.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define PRINT_DETAILS
+
+int failed_already=0;
+PRBool debug_mode = PR_FALSE;
+
+static char *dayOfWeek[] =
+{ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "???" };
+static char *month[] =
+{ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "???"
+};
+
+PRLogModuleInfo *lm;
+
+static void PrintExplodedTime(const PRExplodedTime *et) {
+ PRInt32 totalOffset;
+ PRInt32 hourOffset, minOffset;
+ const char *sign;
+
+ /* Print day of the week, month, day, hour, minute, and second */
+ printf("%s %s %2ld %02ld:%02ld:%02ld ",
+ dayOfWeek[et->tm_wday], month[et->tm_month], et->tm_mday,
+ et->tm_hour, et->tm_min, et->tm_sec);
+
+ /* Print year */
+ printf("%hd ", et->tm_year);
+
+ /* Print time zone */
+ totalOffset = et->tm_params.tp_gmt_offset + et->tm_params.tp_dst_offset;
+ if (totalOffset == 0) {
+ printf("UTC ");
+ } else {
+ sign = "+";
+ if (totalOffset < 0) {
+ totalOffset = -totalOffset;
+ sign = "-";
+ }
+ hourOffset = totalOffset / 3600;
+ minOffset = (totalOffset % 3600) / 60;
+ printf("%s%02ld%02ld ", sign, hourOffset, minOffset);
+ }
+#ifdef PRINT_DETAILS
+ printf("{%d, %d, %d, %d, %d, %d, %d, %d, %d, { %d, %d}}\n",et->tm_usec,
+ et->tm_sec,
+ et->tm_min,
+ et->tm_hour,
+ et->tm_mday,
+ et->tm_month,
+ et->tm_year,
+ et->tm_wday,
+ et->tm_yday,
+ et->tm_params.tp_gmt_offset,
+ et->tm_params.tp_dst_offset);
+#endif
+}
+
+static int ExplodedTimeIsEqual(const PRExplodedTime *et1,
+ const PRExplodedTime *et2)
+{
+ if (et1->tm_usec == et2->tm_usec &&
+ et1->tm_sec == et2->tm_sec &&
+ et1->tm_min == et2->tm_min &&
+ et1->tm_hour == et2->tm_hour &&
+ et1->tm_mday == et2->tm_mday &&
+ et1->tm_month == et2->tm_month &&
+ et1->tm_year == et2->tm_year &&
+ et1->tm_wday == et2->tm_wday &&
+ et1->tm_yday == et2->tm_yday &&
+ et1->tm_params.tp_gmt_offset == et2->tm_params.tp_gmt_offset &&
+ et1->tm_params.tp_dst_offset == et2->tm_params.tp_dst_offset) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+/*
+ * TEST 1: TestExplodeImplodeTime
+ * Description:
+ * For each given timestamp T (a PRTime value), call PR_ExplodeTime
+ * with GMT, US Pacific, and local time parameters. Compare the
+ * resulting calendar (exploded) time values with the expected
+ * values.
+ *
+ * Note: the expected local time values depend on the local time
+ * zone. The local time values stored in this test are for the US
+ * Pacific Time Zone. If you are running this test in a different
+ * time zone, you need to modify the values in the localt array.
+ * An example is provided below.
+ *
+ * Call PR_ImplodeTime for each of the exploded values and compare
+ * the resulting PRTime values with the original input.
+ *
+ * This test is run for the values of time T corresponding to the
+ * following dates:
+ * - 12/31/99 - before 2000
+ * - 01/01/00 - after 2000
+ * - Leap year - Feb 29, 2000
+ * - March 1st, 2001 (after 1 year)
+ * - March 1st, 2005 (after second leap year)
+ * - 09/09/99 (used by some programs as an end of file marker)
+ *
+ * Call PR_Now, convert to calendar time using PR_ExplodeTime and
+ * manually check the result for correctness. The time should match
+ * the system clock.
+ *
+ * Tested functions: PR_Now, PR_ExplodeTime, PR_ImplodeTime,
+ * PR_LocalTimeParameters, PR_GMTParameters.
+ */
+
+static PRTime prt[] = {
+ LL_INIT(220405, 2133125120), /* 946634400000000 */
+ LL_INIT(220425, 2633779200), /* 946720800000000 */
+ LL_INIT(221612, 2107598848), /* 951818400000000 */
+ LL_INIT(228975, 663398400), /* 983440800000000 */
+ LL_INIT(258365, 1974568960), /* 1109671200000000 */
+ 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[] = {
+ { 0, 0, 0, 10, 31, 11, 1999, 5, 364, {0, 0}}, /* 1999/12/31 10:00:00 GMT */
+ { 0, 0, 0, 10, 1, 0, 2000, 6, 0, {0, 0}}, /* 2000/01/01 10:00:00 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 */
+ /* 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[] = {
+ { 0, 0, 0, 2, 31, 11, 1999, 5, 364, {-28800, 0}}, /* 1999/12/31 2:00:00 PST */
+ { 0, 0, 0, 2, 1, 0, 2000, 6, 0, {-28800, 0}}, /* 2000/01/01 2:00:00 PST */
+ { 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 */
+ /* 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 */
+};
+
+/*
+ * This test assumes that we are in US Pacific Time Zone.
+ * If you are running this test in a different time zone,
+ * you need to modify the localt array and fill in the
+ * expected results. The localt array for US Eastern Time
+ * Zone is provided as an example.
+ */
+static PRExplodedTime localt[] = {
+ { 0, 0, 0, 2, 31, 11, 1999, 5, 364, {-28800, 0}}, /* 1999/12/31 2:00:00 PST */
+ { 0, 0, 0, 2, 1, 0, 2000, 6, 0, {-28800, 0}}, /* 2000/01/01 2:00:00 PST */
+ { 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 */
+ /* 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
+static PRExplodedTime localt[] = {
+ { 0, 0, 0, 5, 31, 11, 1999, 5, 364, {-18000, 0}}, /* 1999/12/31 2:00:00 EST */
+ { 0, 0, 0, 5, 1, 0, 2000, 6, 0, {-18000, 0}}, /* 2000/01/01 2:00:00 EST */
+ { 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 */
+ /* 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
+
+static PRStatus TestExplodeImplodeTime(void)
+{
+ PRTime prt_tmp;
+ PRTime now;
+ int idx;
+ int array_size = sizeof(prt) / sizeof(PRTime);
+ PRExplodedTime et_tmp;
+ char buf[1024];
+
+ for (idx = 0; idx < array_size; idx++) {
+ PR_snprintf(buf, sizeof(buf), "%lld", prt[idx]);
+ if (debug_mode) {
+ printf("Time stamp %s\n", buf);
+ }
+ 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);
+ if (LL_NE(prt_tmp, prt[idx])) {
+ fprintf(stderr, "PRTime not equal\n");
+ exit(1);
+ }
+ if (debug_mode) {
+ printf("GMT: ");
+ PrintExplodedTime(&et_tmp);
+ printf("\n");
+ }
+
+ 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);
+ if (LL_NE(prt_tmp, prt[idx])) {
+ fprintf(stderr, "PRTime not equal\n");
+ exit(1);
+ }
+ if (debug_mode) {
+ printf("US Pacific Time: ");
+ PrintExplodedTime(&et_tmp);
+ printf("\n");
+ }
+
+ 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);
+ if (LL_NE(prt_tmp, prt[idx])) {
+ fprintf(stderr, "not equal\n");
+ exit(1);
+ }
+ if (debug_mode) {
+ printf("Local time:");
+ PrintExplodedTime(&et_tmp);
+ printf("\n\n");
+ }
+ }
+
+ now = PR_Now();
+ PR_ExplodeTime(now, PR_GMTParameters, &et_tmp);
+ printf("Current GMT is ");
+ PrintExplodedTime(&et_tmp);
+ printf("\n");
+ prt_tmp = PR_ImplodeTime(&et_tmp);
+ if (LL_NE(prt_tmp, now)) {
+ fprintf(stderr, "not equal\n");
+ exit(1);
+ }
+ PR_ExplodeTime(now, PR_USPacificTimeParameters, &et_tmp);
+ printf("Current US Pacific Time is ");
+ PrintExplodedTime(&et_tmp);
+ printf("\n");
+ prt_tmp = PR_ImplodeTime(&et_tmp);
+ if (LL_NE(prt_tmp, now)) {
+ fprintf(stderr, "not equal\n");
+ exit(1);
+ }
+ PR_ExplodeTime(now, PR_LocalTimeParameters, &et_tmp);
+ printf("Current local time is ");
+ PrintExplodedTime(&et_tmp);
+ printf("\n");
+ prt_tmp = PR_ImplodeTime(&et_tmp);
+ if (LL_NE(prt_tmp, now)) {
+ fprintf(stderr, "not equal\n");
+ exit(1);
+ }
+ printf("Please verify the results\n\n");
+
+ if (debug_mode) {
+ printf("Test 1 passed\n");
+ }
+ return PR_SUCCESS;
+}
+/* End of Test 1: TestExplodeImplodeTime */
+
+/*
+ * Test 2: Normalize Time
+ */
+
+/*
+ * time increment for addition to PRExplodeTime
+ */
+typedef struct time_increment {
+ PRInt32 ti_usec;
+ PRInt32 ti_sec;
+ PRInt32 ti_min;
+ PRInt32 ti_hour;
+} time_increment_t;
+
+/*
+ * Data for testing PR_Normalize
+ * Add the increment to base_time, normalize it to GMT and US Pacific
+ * Time zone.
+ */
+typedef struct normalize_test_data {
+ PRExplodedTime base_time;
+ time_increment_t increment;
+ PRExplodedTime expected_gmt_time;
+ PRExplodedTime expected_uspt_time;
+} normalize_test_data_t;
+
+
+/*
+ * Test data - the base time values cover dates of interest including y2k - 1,
+ * y2k + 1, y2k leap year, y2k leap date + 1year,
+ * y2k leap date + 4 years
+ */
+normalize_test_data_t normalize_test_array[] = {
+ /*usec sec min hour mday mo year wday yday {gmtoff, dstoff }*/
+
+ /* Fri 12/31/1999 19:32:48 PST */
+ { {0, 48, 32, 19, 31, 11, 1999, 5, 364, { -28800, 0}},
+ {0, 0, 30, 20},
+ {0, 48, 2, 0, 2, 0, 2000, 0, 1, { 0, 0}}, /*Sun Jan 2 00:02:48 UTC 2000*/
+ {0, 48, 2, 16, 1, 0, 2000, 6, 0, { -28800, 0}},/* Sat Jan 1 16:02:48
+ PST 2000*/
+ },
+ /* Fri 99-12-31 23:59:02 GMT */
+ { {0, 2, 59, 23, 31, 11, 1999, 5, 364, { 0, 0}},
+ {0, 0, 45, 0},
+ {0, 2, 44, 0, 1, 0, 2000, 6, 0, { 0, 0}},/* Sat Jan 1 00:44:02 UTC 2000*/
+ {0, 2, 44, 16, 31, 11, 1999, 5, 364, { -28800, 0}}/*Fri Dec 31 16:44:02
+ PST 1999*/
+ },
+ /* 99-12-25 12:00:00 GMT */
+ { {0, 0, 0, 12, 25, 11, 1999, 6, 358, { 0, 0}},
+ {0, 0, 0, 364 * 24},
+ {0, 0, 0, 12, 23, 11, 2000, 6, 357, { 0, 0}},/*Sat Dec 23 12:00:00
+ 2000 UTC*/
+ {0, 0, 0, 4, 23, 11, 2000, 6, 357, { -28800, 0}}/*Sat Dec 23 04:00:00
+ 2000 -0800*/
+ },
+ /* 00-01-1 00:00:00 PST */
+ { {0, 0, 0, 0, 1, 0, 2000, 6, 0, { -28800, 0}},
+ {0, 0, 0, 48},
+ {0, 0, 0, 8, 3, 0, 2000, 1, 2, { 0, 0}},/*Mon Jan 3 08:00:00 2000 UTC*/
+ {0, 0, 0, 0, 3, 0, 2000, 1, 2, { -28800, 0}}/*Mon Jan 3 00:00:00 2000
+ -0800*/
+ },
+ /* 00-01-10 12:00:00 PST */
+ { {0, 0, 0, 12, 10, 0, 2000, 1, 9, { -28800, 0}},
+ {0, 0, 0, 364 * 5 * 24},
+ {0, 0, 0, 20, 3, 0, 2005, 1, 2, { 0, 0}},/*Mon Jan 3 20:00:00 2005 UTC */
+ {0, 0, 0, 12, 3, 0, 2005, 1, 2, { -28800, 0}}/*Mon Jan 3 12:00:00
+ 2005 -0800*/
+ },
+ /* 00-02-28 15:39 GMT */
+ { {0, 0, 39, 15, 28, 1, 2000, 1, 58, { 0, 0}},
+ {0, 0, 0, 24},
+ {0, 0, 39, 15, 29, 1, 2000, 2, 59, { 0, 0}}, /*Tue Feb 29 15:39:00 2000
+ UTC*/
+ {0, 0, 39, 7, 29, 1, 2000, 2, 59, { -28800, 0}}/*Tue Feb 29 07:39:00
+ 2000 -0800*/
+ },
+ /* 01-03-01 12:00 PST */
+ { {0, 0, 0, 12, 3, 0, 2001, 3, 2, { -28800, 0}},/*Wed Jan 3 12:00:00
+ -0800 2001*/
+ {0, 30, 30,45},
+ {0, 30, 30, 17, 5, 0, 2001, 5, 4, { 0, 0}}, /*Fri Jan 5 17:30:30 2001
+ UTC*/
+ {0, 30, 30, 9, 5, 0, 2001, 5, 4, { -28800, 0}} /*Fri Jan 5 09:30:30
+ 2001 -0800*/
+ },
+ /* 2004-04-26 12:00 GMT */
+ { {0, 0, 0, 20, 3, 0, 2001, 3, 2, { 0, 0}},
+ {0, 0, 30,0},
+ {0, 0, 30, 20, 3, 0, 2001, 3, 2, { 0, 0}},/*Wed Jan 3 20:30:00 2001 UTC*/
+ {0, 0, 30, 12, 3, 0, 2001, 3, 2, { -28800, 0}}/*Wed Jan 3 12:30:00
+ 2001 -0800*/
+ },
+ /* 99-09-09 00:00 GMT */
+ { {0, 0, 0, 0, 9, 8, 1999, 4, 251, { 0, 0}},
+ {0, 0, 0, 12},
+ {0, 0, 0, 12, 9, 8, 1999, 4, 251, { 0, 0}},/*Thu Sep 9 12:00:00 1999 UTC*/
+ {0, 0, 0, 5, 9, 8, 1999, 4, 251, { -28800, 3600}}/*Thu Sep 9 05:00:00
+ 1999 -0700*/
+ }
+};
+
+void add_time_increment(PRExplodedTime *et1, time_increment_t *it)
+{
+ et1->tm_usec += it->ti_usec;
+ et1->tm_sec += it->ti_sec;
+ et1->tm_min += it->ti_min;
+ et1->tm_hour += it->ti_hour;
+}
+
+/*
+** TestNormalizeTime() -- Test PR_NormalizeTime()
+** For each data item, add the time increment to the base_time and then
+** normalize it for GMT and local time zones. This test assumes that
+** the local time zone is the Pacific Time Zone. The normalized values
+** should match the expected values in the data item.
+**
+*/
+PRStatus TestNormalizeTime(void)
+{
+ int idx, count;
+ normalize_test_data_t *itemp;
+ time_increment_t *itp;
+
+ count = sizeof(normalize_test_array)/sizeof(normalize_test_array[0]);
+ for (idx = 0; idx < count; idx++) {
+ itemp = &normalize_test_array[idx];
+ if (debug_mode) {
+ printf("%2d. %15s",idx +1,"Base time: ");
+ PrintExplodedTime(&itemp->base_time);
+ printf("\n");
+ }
+ itp = &itemp->increment;
+ if (debug_mode) {
+ printf("%20s %2d hrs %2d min %3d sec\n","Add",itp->ti_hour,
+ itp->ti_min, itp->ti_sec);
+ }
+ add_time_increment(&itemp->base_time, &itemp->increment);
+ PR_NormalizeTime(&itemp->base_time, PR_LocalTimeParameters);
+ if (debug_mode) {
+ printf("%19s","PST time: ");
+ PrintExplodedTime(&itemp->base_time);
+ printf("\n");
+ }
+ if (!ExplodedTimeIsEqual(&itemp->base_time,
+ &itemp->expected_uspt_time)) {
+ printf("PR_NormalizeTime failed\n");
+ if (debug_mode) {
+ PrintExplodedTime(&itemp->expected_uspt_time);
+ }
+ return PR_FAILURE;
+ }
+ PR_NormalizeTime(&itemp->base_time, PR_GMTParameters);
+ if (debug_mode) {
+ printf("%19s","GMT time: ");
+ PrintExplodedTime(&itemp->base_time);
+ printf("\n");
+ }
+
+ if (!ExplodedTimeIsEqual(&itemp->base_time,
+ &itemp->expected_gmt_time)) {
+ printf("PR_NormalizeTime failed\n");
+ return PR_FAILURE;
+ }
+ }
+ return PR_SUCCESS;
+}
+
+
+/*
+** ParseTest. Structure defining a string time and a matching exploded time
+**
+*/
+typedef struct ParseTest
+{
+ char *sDate; /* string to be converted using PR_ParseTimeString() */
+ PRExplodedTime et; /* expected result of the conversion */
+} ParseTest;
+
+static ParseTest parseArray[] =
+{
+ /* |<----- expected result ------------------------------------------->| */
+ /* "string to test" usec sec min hour day mo year wday julian {gmtoff, dstoff }*/
+ { "Thursday 1 Jan 1970 00:00:00", { 000000, 00, 00, 00, 1, 0, 1970, 4, 0, {-28800, 0 }}},
+ { "1 Jan 1970 00:00:00", { 000000, 00, 00, 00, 1, 0, 1970, 4, 0, {-28800, 0 }}},
+ { "1-Jan-1970 00:00:00", { 000000, 00, 00, 00, 1, 0, 1970, 4, 0, {-28800, 0 }}},
+ { "01-Jan-1970 00:00:00", { 000000, 00, 00, 00, 1, 0, 1970, 4, 0, {-28800, 0 }}},
+ { "January 1, 1970", { 000000, 00, 00, 00, 1, 0, 1970, 4, 0, {-28800, 0 }}},
+ { "January 1, 1970 00:00", { 000000, 00, 00, 00, 1, 0, 1970, 4, 0, {-28800, 0 }}},
+ { "January 01, 1970 00:00", { 000000, 00, 00, 00, 1, 0, 1970, 4, 0, {-28800, 0 }}},
+ { "January 01 1970 00:00", { 000000, 00, 00, 00, 1, 0, 1970, 4, 0, {-28800, 0 }}},
+ { "January 01 1970 00:00:00", { 000000, 00, 00, 00, 1, 0, 1970, 4, 0, {-28800, 0 }}},
+ { "01-01-1970", { 000000, 00, 00, 00, 1, 0, 1970, 4, 0, {-28800, 0 }}},
+ { "01/01/1970", { 000000, 00, 00, 00, 1, 0, 1970, 4, 0, {-28800, 0 }}},
+ { "01/01/70", { 000000, 00, 00, 00, 1, 0, 1970, 4, 0, {-28800, 0 }}},
+ { "01/01/70 00:00:00", { 000000, 00, 00, 00, 1, 0, 1970, 4, 0, {-28800, 0 }}},
+ { "70/01/01 00:00:00", { 000000, 00, 00, 00, 1, 0, 1970, 4, 0, {-28800, 0 }}},
+ { "70/1/1 00:00:", { 000000, 00, 00, 00, 1, 0, 1970, 4, 0, {-28800, 0 }}},
+ { "00:00 Thursday, January 1, 1970",{ 000000, 00, 00, 00, 1, 0, 1970, 4, 0, {-28800, 0 }}},
+ { "1-Jan-70 00:00:00", { 000000, 00, 00, 00, 1, 0, 1970, 4, 0, {-28800, 0 }}},
+ { "70-01-01 00:00:00", { 000000, 00, 00, 00, 1, 0, 1970, 4, 0, {-28800, 0 }}},
+ { "70/01/01 00:00:00", { 000000, 00, 00, 00, 1, 0, 1970, 4, 0, {-28800, 0 }}},
+
+ /* 31-Dec-1969 */
+ { "Wed 31 Dec 1969 00:00:00", { 000000, 00, 00, 00, 31, 11, 1969, 3, 364, {-28800, 0 }}},
+ { "31 Dec 1969 00:00:00", { 000000, 00, 00, 00, 31, 11, 1969, 3, 364, {-28800, 0 }}},
+ { "12/31/69 00:00:00", { 000000, 00, 00, 00, 31, 11, 2069, 2, 364, {-28800, 0 }}},
+ { "12/31/1969 00:00:00", { 000000, 00, 00, 00, 31, 11, 1969, 3, 364, {-28800, 0 }}},
+ { "12-31-69 00:00:00", { 000000, 00, 00, 00, 31, 11, 2069, 2, 364, {-28800, 0 }}},
+ { "12-31-1969 00:00:00", { 000000, 00, 00, 00, 31, 11, 1969, 3, 364, {-28800, 0 }}},
+ { "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 }}},
+ { "12/31/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 }}},
+ { "12-31-1999 00:00:00", { 000000, 00, 00, 00, 31, 11, 1999, 5, 364, {-28800, 0 }}},
+ { "99-12-31 00:00:00", { 000000, 00, 00, 00, 31, 11, 1999, 5, 364, {-28800, 0 }}},
+ { "99/12/31 00:00:00", { 000000, 00, 00, 00, 31, 11, 1999, 5, 364, {-28800, 0 }}},
+
+ /* 01-Jan-2000 */
+ { "01 Jan 2000 00:00:00", { 000000, 00, 00, 00, 1, 0, 2000, 6, 0, {-28800, 0 }}},
+ { "1/1/00 00:00:00", { 000000, 00, 00, 00, 1, 0, 2000, 6, 0, {-28800, 0 }}},
+ { "1/1/2000 00:00:00", { 000000, 00, 00, 00, 1, 0, 2000, 6, 0, {-28800, 0 }}},
+ { "1-1-00 00:00:00", { 000000, 00, 00, 00, 1, 0, 2000, 6, 0, {-28800, 0 }}},
+ { "1-1-2000 00:00:00", { 000000, 00, 00, 00, 1, 0, 2000, 6, 0, {-28800, 0 }}},
+ { "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 }}},
+ { "2/29/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 }}},
+ { "2-29-2000 00:00:00", { 000000, 00, 00, 00, 29, 1, 2000, 2, 59, {-28800, 0 }}},
+ { "02-29-00 00:00:00", { 000000, 00, 00, 00, 29, 1, 2000, 2, 59, {-28800, 0 }}},
+ { "02-29-2000 00:00:00", { 000000, 00, 00, 00, 29, 1, 2000, 2, 59, {-28800, 0 }}},
+
+ /* 01-Mar-2000 */
+ { "01 Mar 2000 00:00:00", { 000000, 00, 00, 00, 1, 2, 2000, 3, 60, {-28800, 0 }}},
+ { "3/1/00 00:00:00", { 000000, 00, 00, 00, 1, 2, 2000, 3, 60, {-28800, 0 }}},
+ { "3/1/2000 00:00:00", { 000000, 00, 00, 00, 1, 2, 2000, 3, 60, {-28800, 0 }}},
+ { "3-1-00 00:00:00", { 000000, 00, 00, 00, 1, 2, 2000, 3, 60, {-28800, 0 }}},
+ { "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 }}},
+ { "3/1/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 }}},
+ { "3-1-2001 00:00:00", { 000000, 00, 00, 00, 1, 2, 2001, 4, 59, {-28800, 0 }}},
+ { "03-01-01 00:00:00", { 000000, 00, 00, 00, 1, 2, 2001, 4, 59, {-28800, 0 }}},
+ { "03-01-2001 00:00:00", { 000000, 00, 00, 00, 1, 2, 2001, 4, 59, {-28800, 0 }}},
+
+ /* 29-Feb-2004 */
+ { "29 Feb 2004 00:00:00", { 000000, 00, 00, 00, 29, 1, 2004, 0, 59, {-28800, 0 }}},
+ { "2/29/04 00:00:00", { 000000, 00, 00, 00, 29, 1, 2004, 0, 59, {-28800, 0 }}},
+ { "2/29/2004 00:00:00", { 000000, 00, 00, 00, 29, 1, 2004, 0, 59, {-28800, 0 }}},
+ { "2-29-04 00:00:00", { 000000, 00, 00, 00, 29, 1, 2004, 0, 59, {-28800, 0 }}},
+ { "2-29-2004 00:00:00", { 000000, 00, 00, 00, 29, 1, 2004, 0, 59, {-28800, 0 }}},
+
+ /* 01-Mar-2004 */
+ { "01 Mar 2004 00:00:00", { 000000, 00, 00, 00, 1, 2, 2004, 1, 60, {-28800, 0 }}},
+ { "3/1/04 00:00:00", { 000000, 00, 00, 00, 1, 2, 2004, 1, 60, {-28800, 0 }}},
+ { "3/1/2004 00:00:00", { 000000, 00, 00, 00, 1, 2, 2004, 1, 60, {-28800, 0 }}},
+ { "3-1-04 00:00:00", { 000000, 00, 00, 00, 1, 2, 2004, 1, 60, {-28800, 0 }}},
+ { "3-1-2004 00:00:00", { 000000, 00, 00, 00, 1, 2, 2004, 1, 60, {-28800, 0 }}},
+ { "03-01-04 00:00:00", { 000000, 00, 00, 00, 1, 2, 2004, 1, 60, {-28800, 0 }}},
+ { "03-01-2004 00:00:00", { 000000, 00, 00, 00, 1, 2, 2004, 1, 60, {-28800, 0 }}},
+
+ /* 01-Mar-2005 */
+ { "01 Mar 2005 00:00:00", { 000000, 00, 00, 00, 1, 2, 2005, 2, 59, {-28800, 0 }}},
+ { "3/1/05 00:00:00", { 000000, 00, 00, 00, 1, 2, 2005, 2, 59, {-28800, 0 }}},
+ { "3/1/2005 00:00:00", { 000000, 00, 00, 00, 1, 2, 2005, 2, 59, {-28800, 0 }}},
+ { "3-1-05 00:00:00", { 000000, 00, 00, 00, 1, 2, 2005, 2, 59, {-28800, 0 }}},
+ { "3-1-2005 00:00:00", { 000000, 00, 00, 00, 1, 2, 2005, 2, 59, {-28800, 0 }}},
+ { "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 }}},
+
+ /* last element. string must be null */
+ { NULL }
+}; /* end array of ParseTest */
+
+/*
+** TestParseTime() -- Test PR_ParseTimeString() for y2k compliance
+**
+** TestParseTime() loops thru the array parseArray. For each element in
+** the array, he calls PR_ParseTimeString() with sDate as the conversion
+** argument. The result (ct) is then converted to a PRExplodedTime structure
+** and compared with the exploded time value (parseArray[n].et) in the
+** array element; if equal, the element passes the test.
+**
+** The array parseArray[] contains entries that are interesting to the
+** y2k problem.
+**
+**
+*/
+static PRStatus TestParseTime( void )
+{
+ ParseTest *ptp = parseArray;
+ PRTime ct;
+ PRExplodedTime cet;
+ char *sp = ptp->sDate;
+ PRStatus rc;
+ PRStatus rv = PR_SUCCESS;
+
+ while ( sp != NULL)
+ {
+ rc = PR_ParseTimeString( sp, PR_FALSE, &ct );
+ if ( PR_FAILURE == rc )
+ {
+ printf("TestParseTime(): PR_ParseTimeString() failed to convert: %s\n", sp );
+ rv = PR_FAILURE;
+ failed_already = 1;
+ }
+ else
+ {
+ PR_ExplodeTime( ct, PR_LocalTimeParameters, &cet );
+
+ if ( !ExplodedTimeIsEqual( &cet, &ptp->et ))
+ {
+ printf("TestParseTime(): Exploded time compare failed: %s\n", sp );
+ if ( debug_mode )
+ {
+ PrintExplodedTime( &cet );
+ printf("\n");
+ PrintExplodedTime( &ptp->et );
+ printf("\n");
+ }
+
+ rv = PR_FAILURE;
+ failed_already = 1;
+ }
+ }
+
+ /* point to next element in array, keep going */
+ ptp++;
+ sp = ptp->sDate;
+ } /* end while() */
+
+ return( rv );
+} /* end TestParseTime() */
+
+int main(int argc, char** argv)
+{
+ /* The command line argument: -d is used to determine if the test is being run
+ in debug mode. The regress tool requires only one line output:PASS or FAIL.
+ All of the printfs associated with this test has been handled with a if (debug_mode)
+ test.
+ Usage: test_name -d
+ */
+ PLOptStatus os;
+ PLOptState *opt;
+
+ PR_STDIO_INIT();
+ opt = PL_CreateOptState(argc, argv, "d");
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 'd': /* debug mode */
+ debug_mode = PR_TRUE;
+ break;
+ default:
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ /* main test */
+
+ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
+ lm = PR_NewLogModule("test");
+
+ if ( PR_FAILURE == TestExplodeImplodeTime())
+ {
+ PR_LOG( lm, PR_LOG_ERROR,
+ ("TestExplodeImplodeTime() failed"));
+ }
+ else {
+ printf("Test 1: Calendar Time Test passed\n");
+ }
+
+ if ( PR_FAILURE == TestNormalizeTime())
+ {
+ PR_LOG( lm, PR_LOG_ERROR,
+ ("TestNormalizeTime() failed"));
+ }
+ else {
+ printf("Test 2: Normalize Time Test passed\n");
+ }
+
+ if ( PR_FAILURE == TestParseTime())
+ {
+ PR_LOG( lm, PR_LOG_ERROR,
+ ("TestParseTime() failed"));
+ }
+ else {
+ printf("Test 3: Parse Time Test passed\n");
+ }
+
+ if (failed_already) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+} /* end main() y2k.c */
+
diff --git a/nsprpub/pr/tests/y2ktmo.c b/nsprpub/pr/tests/y2ktmo.c
new file mode 100644
index 0000000000..b28467e4d5
--- /dev/null
+++ b/nsprpub/pr/tests/y2ktmo.c
@@ -0,0 +1,554 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * 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)
+#if defined(WINCE)
+#include <windows.h>
+#else
+#include <sys/types.h>
+#include <sys/timeb.h> /* for _ftime */
+#endif
+#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)
+#if defined(WINCE)
+static DWORD start_time_tick;
+#else
+static struct _timeb start_time_tb;
+#endif
+#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) && !defined(WINCE)
+ 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)
+#if defined(WINCE)
+ elapsed_msecs = GetTickCount() - start_time_tick;
+#else
+ _ftime(&end_time_tb);
+ elapsed_msecs = 1000*(end_time_tb.time - start_time_tb.time)
+ + (end_time_tb.millitm - start_time_tb.millitm);
+#endif
+#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) && !defined(WINCE)
+ 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)
+#if defined(WINCE)
+ elapsed_msecs = GetTickCount() - start_time_tick;
+#else
+ _ftime(&end_time_tb);
+ elapsed_msecs = 1000*(end_time_tb.time - start_time_tb.time)
+ + (end_time_tb.millitm - start_time_tb.millitm);
+#endif
+#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) && !defined(WINCE)
+ 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)
+#if defined(WINCE)
+ elapsed_msecs = GetTickCount() - start_time_tick;
+#else
+ _ftime(&end_time_tb);
+ elapsed_msecs = 1000*(end_time_tb.time - start_time_tb.time)
+ + (end_time_tb.millitm - start_time_tb.millitm);
+#endif
+#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) && !defined(WINCE)
+ 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)
+#if defined(WINCE)
+ elapsed_msecs = GetTickCount() - start_time_tick;
+#else
+ _ftime(&end_time_tb);
+ elapsed_msecs = 1000*(end_time_tb.time - start_time_tb.time)
+ + (end_time_tb.millitm - start_time_tb.millitm);
+#endif
+#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) && !defined(WINCE)
+ 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)
+#if defined(WINCE)
+ elapsed_msecs = GetTickCount() - start_time_tick;
+#else
+ _ftime(&end_time_tb);
+ elapsed_msecs = 1000*(end_time_tb.time - start_time_tb.time)
+ + (end_time_tb.millitm - start_time_tb.millitm);
+#endif
+#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) && !defined(WINCE)
+ 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)
+#if defined(WINCE)
+ elapsed_msecs = GetTickCount() - start_time_tick;
+#else
+ _ftime(&end_time_tb);
+ elapsed_msecs = 1000*(end_time_tb.time - start_time_tb.time)
+ + (end_time_tb.millitm - start_time_tb.millitm);
+#endif
+#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)
+#ifdef WINCE
+ start_time_tick = GetTickCount();
+#else
+ _ftime(&start_time_tb);
+#endif
+#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;
+}
diff --git a/nsprpub/pr/tests/yield.c b/nsprpub/pr/tests/yield.c
new file mode 100644
index 0000000000..eb55926b58
--- /dev/null
+++ b/nsprpub/pr/tests/yield.c
@@ -0,0 +1,57 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include <stdio.h>
+#include "prthread.h"
+#include "prinit.h"
+#ifndef XP_OS2
+#include "private/pprmisc.h"
+#include <windows.h>
+#else
+#include "primpl.h"
+#include <os2.h>
+#endif
+
+#define THREADS 10
+
+
+void
+threadmain(void *_id)
+{
+ int id = (int)_id;
+ int index;
+
+ printf("thread %d alive\n", id);
+ for (index=0; index<10; index++) {
+ printf("thread %d yielding\n", id);
+ PR_Sleep(0);
+ printf("thread %d awake\n", id);
+ }
+ printf("thread %d dead\n", id);
+
+}
+
+int main(int argc, char **argv)
+{
+ int index;
+ PRThread *a[THREADS];
+
+ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 5);
+ PR_STDIO_INIT();
+
+ for (index=0; index<THREADS; index++) {
+ a[index] = PR_CreateThread(PR_USER_THREAD,
+ threadmain,
+ (void *)index,
+ PR_PRIORITY_NORMAL,
+ index%2?PR_LOCAL_THREAD:PR_GLOBAL_THREAD,
+ PR_JOINABLE_THREAD,
+ 0);
+ }
+ for(index=0; index<THREADS; index++) {
+ PR_JoinThread(a[index]);
+ }
+ printf("main dying\n");
+}
diff --git a/nsprpub/pr/tests/zerolen.c b/nsprpub/pr/tests/zerolen.c
new file mode 100644
index 0000000000..a84bd43228
--- /dev/null
+++ b/nsprpub/pr/tests/zerolen.c
@@ -0,0 +1,250 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * Test: zerolen.c
+ *
+ * Description: a test for Bugzilla bug #17699. We perform
+ * the same test for PR_Writev, PR_Write, and PR_Send. In
+ * each test the server thread first fills up the connection
+ * to the client so that the next write operation will fail
+ * with EAGAIN. Then it calls PR_Writev, PR_Write, or PR_Send
+ * with a zero-length buffer. The client thread initially
+ * does not read so that the connection can be filled up.
+ * Then it empties the connection so that the server thread's
+ * PR_Writev, PR_Write, or PR_Send call can succeed.
+ *
+ * Bug #17699 is specific to the pthreads version on Unix,
+ * so on other platforms this test does nothing.
+ */
+
+#ifndef XP_UNIX
+
+#include <stdio.h>
+
+int main(int argc, char **argv)
+{
+ printf("PASS\n");
+ return 0;
+}
+
+#else /* XP_UNIX */
+
+#include "nspr.h"
+#include "private/pprio.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+
+static void ClientThread(void *arg)
+{
+ PRFileDesc *sock;
+ PRNetAddr addr;
+ PRUint16 port = (PRUint16) arg;
+ char buf[1024];
+ PRInt32 nbytes;
+
+ sock = PR_NewTCPSocket();
+ if (NULL == sock) {
+ fprintf(stderr, "PR_NewTCPSocket failed\n");
+ exit(1);
+ }
+ if (PR_InitializeNetAddr(PR_IpAddrLoopback, port, &addr) == PR_FAILURE) {
+ fprintf(stderr, "PR_InitializeNetAddr failed\n");
+ exit(1);
+ }
+ if (PR_Connect(sock, &addr, PR_INTERVAL_NO_TIMEOUT) == PR_FAILURE) {
+ fprintf(stderr, "PR_Connect failed\n");
+ exit(1);
+ }
+ /*
+ * Sleep 5 seconds to force the server thread to get EAGAIN.
+ */
+ if (PR_Sleep(PR_SecondsToInterval(5)) == PR_FAILURE) {
+ fprintf(stderr, "PR_Sleep failed\n");
+ exit(1);
+ }
+ /*
+ * Then start reading.
+ */
+ while (nbytes = PR_Read(sock, buf, sizeof(buf)) > 0) {
+ /* empty loop body */
+ }
+ if (-1 == nbytes) {
+ fprintf(stderr, "PR_Read failed\n");
+ exit(1);
+ }
+ if (PR_Close(sock) == PR_FAILURE) {
+ fprintf(stderr, "PR_Close failed\n");
+ exit(1);
+ }
+}
+
+int main()
+{
+ PRFileDesc *listenSock;
+ PRFileDesc *acceptSock;
+ int osfd;
+ PRThread *clientThread;
+ PRNetAddr addr;
+ char buf[1024];
+ PRInt32 nbytes;
+ PRIOVec iov;
+
+ memset(buf, 0, sizeof(buf)); /* Initialize the buffer. */
+ listenSock = PR_NewTCPSocket();
+ if (NULL == listenSock) {
+ fprintf(stderr, "PR_NewTCPSocket failed\n");
+ exit(1);
+ }
+ if (PR_InitializeNetAddr(PR_IpAddrAny, 0, &addr) == PR_FAILURE) {
+ fprintf(stderr, "PR_InitializeNetAddr failed\n");
+ exit(1);
+ }
+ if (PR_Bind(listenSock, &addr) == PR_FAILURE) {
+ fprintf(stderr, "PR_Bind failed\n");
+ exit(1);
+ }
+ /* Find out what port number we are bound to. */
+ if (PR_GetSockName(listenSock, &addr) == PR_FAILURE) {
+ fprintf(stderr, "PR_GetSockName failed\n");
+ exit(1);
+ }
+ if (PR_Listen(listenSock, 5) == PR_FAILURE) {
+ fprintf(stderr, "PR_Listen failed\n");
+ exit(1);
+ }
+
+ /*
+ * First test PR_Writev.
+ */
+ clientThread = PR_CreateThread(PR_USER_THREAD,
+ ClientThread, (void *) PR_ntohs(PR_NetAddrInetPort(&addr)),
+ PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0);
+ if (NULL == clientThread) {
+ fprintf(stderr, "PR_CreateThread failed\n");
+ exit(1);
+ }
+ acceptSock = PR_Accept(listenSock, NULL, PR_INTERVAL_NO_TIMEOUT);
+ if (NULL == acceptSock) {
+ fprintf(stderr, "PR_Accept failed\n");
+ exit(1);
+ }
+ osfd = PR_FileDesc2NativeHandle(acceptSock);
+ while (write(osfd, buf, sizeof(buf)) != -1) {
+ /* empty loop body */
+ }
+ if ((errno != EAGAIN) && (errno != EWOULDBLOCK)) {
+ fprintf(stderr, "write failed\n");
+ exit(1);
+ }
+ iov.iov_base = buf;
+ iov.iov_len = 0;
+ printf("calling PR_Writev with a zero-length buffer\n");
+ fflush(stdout);
+ nbytes = PR_Writev(acceptSock, &iov, 1, PR_INTERVAL_NO_TIMEOUT);
+ if (nbytes != 0) {
+ fprintf(stderr, "PR_Writev should return 0 but returns %d\n", nbytes);
+ exit(1);
+ }
+ if (PR_Close(acceptSock) == PR_FAILURE) {
+ fprintf(stderr, "PR_Close failed\n");
+ exit(1);
+ }
+ if (PR_JoinThread(clientThread) == PR_FAILURE) {
+ fprintf(stderr, "PR_JoinThread failed\n");
+ exit(1);
+ }
+
+ /*
+ * Then test PR_Write.
+ */
+ clientThread = PR_CreateThread(PR_USER_THREAD,
+ ClientThread, (void *) PR_ntohs(PR_NetAddrInetPort(&addr)),
+ PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0);
+ if (NULL == clientThread) {
+ fprintf(stderr, "PR_CreateThread failed\n");
+ exit(1);
+ }
+ acceptSock = PR_Accept(listenSock, NULL, PR_INTERVAL_NO_TIMEOUT);
+ if (NULL == acceptSock) {
+ fprintf(stderr, "PR_Accept failed\n");
+ exit(1);
+ }
+ osfd = PR_FileDesc2NativeHandle(acceptSock);
+ while (write(osfd, buf, sizeof(buf)) != -1) {
+ /* empty loop body */
+ }
+ if ((errno != EAGAIN) && (errno != EWOULDBLOCK)) {
+ fprintf(stderr, "write failed\n");
+ exit(1);
+ }
+ printf("calling PR_Write with a zero-length buffer\n");
+ fflush(stdout);
+ nbytes = PR_Write(acceptSock, buf, 0);
+ if (nbytes != 0) {
+ fprintf(stderr, "PR_Write should return 0 but returns %d\n", nbytes);
+ exit(1);
+ }
+ if (PR_Close(acceptSock) == PR_FAILURE) {
+ fprintf(stderr, "PR_Close failed\n");
+ exit(1);
+ }
+ if (PR_JoinThread(clientThread) == PR_FAILURE) {
+ fprintf(stderr, "PR_JoinThread failed\n");
+ exit(1);
+ }
+
+ /*
+ * Finally test PR_Send.
+ */
+ clientThread = PR_CreateThread(PR_USER_THREAD,
+ ClientThread, (void *) PR_ntohs(PR_NetAddrInetPort(&addr)),
+ PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0);
+ if (NULL == clientThread) {
+ fprintf(stderr, "PR_CreateThread failed\n");
+ exit(1);
+ }
+ acceptSock = PR_Accept(listenSock, NULL, PR_INTERVAL_NO_TIMEOUT);
+ if (NULL == acceptSock) {
+ fprintf(stderr, "PR_Accept failed\n");
+ exit(1);
+ }
+ osfd = PR_FileDesc2NativeHandle(acceptSock);
+ while (write(osfd, buf, sizeof(buf)) != -1) {
+ /* empty loop body */
+ }
+ if ((errno != EAGAIN) && (errno != EWOULDBLOCK)) {
+ fprintf(stderr, "write failed\n");
+ exit(1);
+ }
+ printf("calling PR_Send with a zero-length buffer\n");
+ fflush(stdout);
+ nbytes = PR_Send(acceptSock, buf, 0, 0, PR_INTERVAL_NO_TIMEOUT);
+ if (nbytes != 0) {
+ fprintf(stderr, "PR_Send should return 0 but returns %d\n", nbytes);
+ exit(1);
+ }
+ if (PR_Close(acceptSock) == PR_FAILURE) {
+ fprintf(stderr, "PR_Close failed\n");
+ exit(1);
+ }
+ if (PR_JoinThread(clientThread) == PR_FAILURE) {
+ fprintf(stderr, "PR_JoinThread failed\n");
+ exit(1);
+ }
+
+ if (PR_Close(listenSock) == PR_FAILURE) {
+ fprintf(stderr, "PR_Close failed\n");
+ exit(1);
+ }
+ printf("PASS\n");
+ return 0;
+}
+
+#endif /* XP_UNIX */