diff options
Diffstat (limited to 'nsprpub/pr/src/cplus/tests')
-rw-r--r-- | nsprpub/pr/src/cplus/tests/Makefile.in | 221 | ||||
-rw-r--r-- | nsprpub/pr/src/cplus/tests/fileio.cpp | 33 | ||||
-rw-r--r-- | nsprpub/pr/src/cplus/tests/interval.cpp | 101 | ||||
-rw-r--r-- | nsprpub/pr/src/cplus/tests/ranfile.cpp | 400 | ||||
-rw-r--r-- | nsprpub/pr/src/cplus/tests/switch.cpp | 234 | ||||
-rw-r--r-- | nsprpub/pr/src/cplus/tests/thread.cpp | 108 | ||||
-rw-r--r-- | nsprpub/pr/src/cplus/tests/time.cpp | 29 | ||||
-rw-r--r-- | nsprpub/pr/src/cplus/tests/tpd.cpp | 336 |
8 files changed, 1462 insertions, 0 deletions
diff --git a/nsprpub/pr/src/cplus/tests/Makefile.in b/nsprpub/pr/src/cplus/tests/Makefile.in new file mode 100644 index 000000000..c16423872 --- /dev/null +++ b/nsprpub/pr/src/cplus/tests/Makefile.in @@ -0,0 +1,221 @@ +# +# 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 + +ifeq ($(OS_TARGET), WIN16) +OS_CFLAGS = $(OS_EXE_CFLAGS) +endif + +CXXSRCS = \ + ranfile.cpp \ + thread.cpp \ + interval.cpp \ + time.cpp \ + fileio.cpp \ + switch.cpp \ + tpd.cpp \ + $(NULL) + +OBJS = $(addprefix $(OBJDIR)/,$(CXXSRCS:.cpp=.$(OBJ_SUFFIX))) + +ifeq (,$(filter-out WINNT OS2,$(OS_ARCH))) +PROG_SUFFIX = .exe +else +PROG_SUFFIX = +endif + +PROGS = $(addprefix $(OBJDIR)/, $(CXXSRCS:.cpp=$(PROG_SUFFIX))) + +TARGETS = $(PROGS) $(OBJS) + +INCLUDES = -I.. -I$(dist_includedir) + +# Setting the variables LDOPTS and LIBPR. We first initialize +# them to the default values, then adjust them for some platforms. +LDOPTS = -L$(dist_libdir) +LIBPR = -lnspr$(MOD_MAJOR_VERSION) +LIBPL = -lplc$(MOD_MAJOR_VERSION) + +ifeq ($(OS_ARCH), IRIX) + LDOPTS += -rpath $(PWD)/$(dist_libdir) -rdata_shared + # For 6.x machines, include this flag + ifeq ($(basename $(OS_RELEASE)),6) + ifeq ($(USE_N32),1) + LDOPTS += -n32 + else + LDOPTS += -32 + endif + + ifeq ($(USE_PTHREADS), 1) + ifeq ($(OS_RELEASE), 6.2) + LDOPTS += -Wl,-woff,85 + endif + endif + endif +endif + +# Solaris +ifeq ($(OS_ARCH), SunOS) + ifdef NS_USE_GCC + LDOPTS += -Xlinker -R -Xlinker $(PWD)/$(dist_libdir) + else + LDOPTS += -R $(PWD)/$(dist_libdir) + endif + +# SunOS 5.5 needs to link with -lpthread, even though we already +# linked with this system library when we built libnspr.so. + ifeq ($(OS_RELEASE), 5.5) + ifdef USE_PTHREADS + EXTRA_LIBS = -lpthread + endif + endif +endif # SunOS + +ifeq ($(OS_ARCH), WINNT) +ifeq ($(OS_TARGET), WIN16) + LIBPR = $(dist_libdir)/nspr$(MOD_MAJOR_VERSION).lib + LIBPL = $(dist_libdir)/plc$(MOD_MAJOR_VERSION).lib +else + LDOPTS = -NOLOGO -DEBUG -INCREMENTAL:NO + LIBPR = $(dist_libdir)/libnspr$(MOD_MAJOR_VERSION).$(LIB_SUFFIX) + LIBPL = $(dist_libdir)/libplc$(MOD_MAJOR_VERSION).$(LIB_SUFFIX) +endif +endif + +ifeq ($(OS_ARCH),OS2) +LDOPTS += -Zomf -Zlinker /PM:VIO -lstdcpp +endif + +ifneq ($(OS_ARCH), WINNT) +PWD = $(shell pwd) +endif + +ifeq ($(OS_ARCH), OSF1) +LDOPTS += -rpath $(PWD)/$(dist_libdir) +endif + +ifeq ($(OS_ARCH), HP-UX) + LDOPTS += -Wl,+s,+b,$(PWD)/$(dist_libdir) +endif + +# AIX +ifeq ($(OS_ARCH),AIX) + LDOPTS += -blibpath:$(PWD)/$(dist_libdir):/usr/lib:/lib + ifeq ($(OS_ARCH)$(OS_RELEASE),AIX4.1) + LIBPR = -lnspr$(MOD_MAJOR_VERSION)_shr + LIBPLC = -lplc$(MOD_MAJOR_VERSION)_shr + else + LDOPTS += -brtl + EXTRA_LIBS = -ldl + endif +endif + +ifeq ($(OS_ARCH), Linux) + ifeq ($(OS_RELEASE), 1.2) + EXTRA_LIBS = -ldl + else + LDOPTS += -Xlinker -rpath $(PWD)/$(dist_libdir) + ifeq ($(USE_PTHREADS),1) + EXTRA_LIBS = -lpthread + endif + endif +endif + +ifeq ($(OS_ARCH), SCO_SV) +# 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 = $(PWD)/$(dist_libdir) +endif + +ifeq ($(OS_ARCH), UNIXWARE) +export LD_RUN_PATH = $(PWD)/$(dist_libdir) +endif + +##################################################### +# +# The rules +# +##################################################### + +include $(topsrcdir)/config/rules.mk + +AIX_PRE_4_2 = 0 +ifeq ($(OS_ARCH),AIX) +ifneq ($(OS_RELEASE),4.2) +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 ($(OS_ARCH), WINNT) +ifeq ($(OS_TARGET),WIN16) + echo system windows >w16link + echo option map >>w16link + echo option stack=10K >>w16link + echo option heapsize=32K >>w16link + echo debug $(DEBUGTYPE) all >>w16link + echo name $@ >>w16link + echo file >>w16link + echo $< >>w16link + echo library >>w16link + echo $(LIBPR), >>w16link + echo $(LIBPL), >>w16link + echo winsock.lib >>w16link + wlink @w16link. +else + link $(LDOPTS) $< $(LIBPR) $(LIBPL) ws2_32.lib -out:$@ +endif +else +ifeq ($(OS_ARCH),OS2) + $(LINK) $(LDOPTS) $< $(LIBGC) $(LIBPLC) $(LIBPR) $(OS_LIBS) $(EXTRA_LIBS) -o $@ +else + $(CCC) $(XCFLAGS) $< $(LDOPTS) $(LIBPR) $(LIBPL) $(EXTRA_LIBS) -o $@ +endif +endif +endif + +export:: $(TARGETS) +clean:: + rm -f $(TARGETS) + diff --git a/nsprpub/pr/src/cplus/tests/fileio.cpp b/nsprpub/pr/src/cplus/tests/fileio.cpp new file mode 100644 index 000000000..fdffe9997 --- /dev/null +++ b/nsprpub/pr/src/cplus/tests/fileio.cpp @@ -0,0 +1,33 @@ +/* -*- 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/. */ + +/* fileio.cpp - a test program */ + +#include "rcfileio.h" + +#include <prlog.h> +#include <prprf.h> + +#define DEFAULT_ITERATIONS 100 + +PRIntn main(PRIntn argc, char **argv) +{ + PRStatus rv; + RCFileIO fd; + RCFileInfo info; + rv = fd.Open("filio.dat", PR_CREATE_FILE, 0666); + PR_ASSERT(PR_SUCCESS == rv); + rv = fd.FileInfo(&info); + PR_ASSERT(PR_SUCCESS == rv); + rv = fd.Delete("filio.dat"); + PR_ASSERT(PR_SUCCESS == rv); + fd.Close(); + PR_ASSERT(PR_SUCCESS == rv); + + return 0; +} /* main */ + +/* interval.cpp */ + diff --git a/nsprpub/pr/src/cplus/tests/interval.cpp b/nsprpub/pr/src/cplus/tests/interval.cpp new file mode 100644 index 000000000..8acf50625 --- /dev/null +++ b/nsprpub/pr/src/cplus/tests/interval.cpp @@ -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/. */ + +/* interval.cpp - a test program */ + +#include "rclock.h" +#include "rcthread.h" +#include "rcinrval.h" +#include "rccv.h" + +#include <prio.h> +#include <prlog.h> +#include <prprf.h> + +#define DEFAULT_ITERATIONS 100 + +PRIntn main(PRIntn argc, char **argv) +{ + RCLock ml; + PRStatus rv; + RCCondition cv(&ml); + + RCInterval now, timeout, epoch, elapsed; + PRFileDesc *output = PR_GetSpecialFD(PR_StandardOutput); + PRIntn msecs, seconds, loops, iterations = DEFAULT_ITERATIONS; + + /* slow, agonizing waits */ + for (seconds = 0; seconds < 10; ++seconds) + { + timeout = RCInterval::FromSeconds(seconds); + cv.SetTimeout(timeout); + { + RCEnter lock(&ml); + + epoch.SetToNow(); + + rv = cv.Wait(); + PR_ASSERT(PR_SUCCESS == rv); + + now = RCInterval(RCInterval::now); + elapsed = now - epoch; + } + + PR_fprintf( + output, "Waiting %u seconds took %s%u milliseconds\n", + seconds, ((elapsed < timeout)? "**" : ""), + elapsed.ToMilliseconds()); + } + + /* more slow, agonizing sleeps */ + for (seconds = 0; seconds < 10; ++seconds) + { + timeout = RCInterval::FromSeconds(seconds); + { + epoch.SetToNow(); + + rv = RCThread::Sleep(timeout); + PR_ASSERT(PR_SUCCESS == rv); + + now = RCInterval(RCInterval::now); + elapsed = now - epoch; + } + + PR_fprintf( + output, "Sleeping %u seconds took %s%u milliseconds\n", + seconds, ((elapsed < timeout)? "**" : ""), + elapsed.ToMilliseconds()); + } + + /* fast, spritely little devils */ + for (msecs = 10; msecs < 100; msecs += 10) + { + timeout = RCInterval::FromMilliseconds(msecs); + cv.SetTimeout(timeout); + { + RCEnter lock(&ml); + + epoch.SetToNow(); + + for (loops = 0; loops < iterations; ++loops) + { + rv = cv.Wait(); + PR_ASSERT(PR_SUCCESS == rv); + } + + now = RCInterval(RCInterval::now); + elapsed = now - epoch; + } + elapsed /= iterations; + + PR_fprintf( + output, "Waiting %u msecs took %s%u milliseconds average\n", + msecs, ((elapsed < timeout)? "**" : ""), elapsed.ToMilliseconds()); + } + return 0; +} /* main */ + +/* interval.cpp */ + diff --git a/nsprpub/pr/src/cplus/tests/ranfile.cpp b/nsprpub/pr/src/cplus/tests/ranfile.cpp new file mode 100644 index 000000000..c3ac0d3a4 --- /dev/null +++ b/nsprpub/pr/src/cplus/tests/ranfile.cpp @@ -0,0 +1,400 @@ +/* -*- 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<mailto: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 <prprf.h> +#include <prio.h> + +#include "rccv.h" +#include "rcthread.h" +#include "rcfileio.h" +#include "rclock.h" + +#include <string.h> +#include <stdio.h> +#include <stdlib.h> + +static PRFileDesc *output; +static PRIntn debug_mode = 0; +static PRIntn failed_already = 0; + +class HammerData +{ +public: + typedef enum { + sg_go, sg_stop, sg_done} Action; + typedef enum { + sg_okay, sg_open, sg_close, sg_delete, sg_write, sg_seek} Problem; + + virtual ~HammerData(); + HammerData(RCLock* lock, RCCondition *cond, PRUint32 clip); + virtual PRUint32 Random(); + + Action action; + Problem problem; + PRUint32 writes; + RCInterval timein; +friend class Hammer; +private: + RCLock *ml; + RCCondition *cv; + PRUint32 limit; + + PRFloat64 seed; +}; /* HammerData */ + +class Hammer: public HammerData, public RCThread +{ +public: + virtual ~Hammer(); + Hammer(RCThread::Scope scope, RCLock* lock, RCCondition *cond, PRUint32 clip); + +private: + void RootFunction(); + +}; + +static PRInt32 pageSize = 1024; +static const char* baseName = "./"; +static const char *programName = "Random File"; + +/*********************************************************************** +** PRIVATE FUNCTION: Random +** 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. +***********************************************************************/ +PRUint32 HammerData::Random() +{ + PRUint32 rv; + PRUint64 shift; + RCInterval now = RCInterval(RCInterval::now); + PRFloat64 random = seed * (PRFloat64)((PRIntervalTime)now); + LL_USHR(shift, *((PRUint64*)&random), 16); + LL_L2UI(rv, shift); + seed = (PRFloat64)rv; + return rv; +} /* HammerData::Random */ + +Hammer::~Hammer() { } + +Hammer::Hammer( + RCThread::Scope scope, RCLock* lock, RCCondition *cond, PRUint32 clip): + HammerData(lock, cond, clip), RCThread(scope, RCThread::joinable, 0) { } + +HammerData::~HammerData() { } + +HammerData::HammerData(RCLock* lock, RCCondition *cond, PRUint32 clip) +{ + ml = lock; + cv = cond; + writes = 0; + limit = clip; + seed = 0x58a9382; + action = HammerData::sg_go; + problem = HammerData::sg_okay; + timein = RCInterval(RCInterval::now); +} /* HammerData::HammerData */ + + +/*********************************************************************** +** PRIVATE FUNCTION: Hammer::RootFunction +** 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 +***********************************************************************/ +void Hammer::RootFunction() +{ + PRUint32 index; + RCFileIO file; + char filename[30]; + const char zero = 0; + PRStatus rv = PR_SUCCESS; + + limit = (Random() % limit) + 1; + + (void)sprintf(filename, "%ssg%04p.dat", baseName, this); + + if (debug_mode) PR_fprintf(output, "Starting work on %s\n", filename); + + while (PR_TRUE) + { + PRUint64 bytes; + PRUint32 minor = (Random() % limit) + 1; + PRUint32 random = (Random() % limit) + 1; + PRUint32 pages = (Random() % limit) + 10; + while (minor-- > 0) + { + problem = sg_okay; + if (action != sg_go) goto finished; + problem = sg_open; + rv = file.Open(filename, PR_RDWR|PR_CREATE_FILE, 0666); + if (PR_FAILURE == rv) goto finished; + for (index = 0; index < pages; index++) + { + problem = sg_okay; + if (action != sg_go) goto close; + problem = sg_seek; + bytes = file.Seek(pageSize * index, RCFileIO::set); + if (bytes != pageSize * index) goto close; + problem = sg_write; + bytes = file.Write(&zero, sizeof(zero)); + if (bytes <= 0) goto close; + writes += 1; + } + problem = sg_close; + rv = file.Close(); + if (rv != PR_SUCCESS) goto purge; + + problem = sg_okay; + if (action != sg_go) goto purge; + + problem = sg_open; + rv = file.Open(filename, PR_RDWR, 0666); + if (PR_FAILURE == rv) goto finished; + for (index = 0; index < pages; index++) + { + problem = sg_okay; + if (action != sg_go) goto close; + problem = sg_seek; + bytes = file.Seek(pageSize * index, RCFileIO::set); + if (bytes != pageSize * index) goto close; + problem = sg_write; + bytes = file.Write(&zero, sizeof(zero)); + if (bytes <= 0) goto close; + writes += 1; + random = (random + 511) % pages; + } + problem = sg_close; + rv = file.Close(); + if (rv != PR_SUCCESS) goto purge; + problem = sg_delete; + rv = file.Delete(filename); + if (rv != PR_SUCCESS) goto finished; + } + } + +close: + (void)file.Close(); +purge: + (void)file.Delete(filename); +finished: + RCEnter scope(ml); + action = HammerData::sg_done; + cv->Notify(); + + if (debug_mode) PR_fprintf(output, "Ending work on %s\n", filename); + + return; +} /* Hammer::RootFunction */ + +static Hammer* hammer[100]; +/*********************************************************************** +** 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 virtual_procs 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: max_virtual_procs = 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..'max_virtual_procs') repeat [1..5] +** 7) Print accumulated results and exit +** +** Characteristic output (from IRIX) +** Random File: Using max_virtual_procs = 2, threads = 10, limit = 57 +** Random File: [min [avg] max] writes/sec average +***********************************************************************/ +PRIntn main (PRIntn argc, char *argv[]) +{ + RCLock ml; + PLOptStatus os; + RCCondition cv(&ml); + PRUint32 writesMax = 0, durationTot = 0; + RCThread::Scope thread_scope = RCThread::local; + PRUint32 writes, writesMin = 0x7fffffff, writesTot = 0; + PRIntn active, poll, limit = 0, max_virtual_procs = 0, threads = 0, virtual_procs; + RCInterval interleave(RCInterval::FromMilliseconds(10000)), duration(0); + + const char *where[] = {"okay", "open", "close", "delete", "write", "seek"}; + + 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 0: + baseName = opt->value; + break; + case 'G': /* global threads */ + thread_scope = RCThread::global; + 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 */ + max_virtual_procs = atoi(opt->value); + break; + default: + break; + } + } + PL_DestroyOptState(opt); + output = PR_GetSpecialFD(PR_StandardOutput); + + /* main test */ + + cv.SetTimeout(interleave); + + if (max_virtual_procs == 0) max_virtual_procs = 2; + if (limit == 0) limit = 57; + if (threads == 0) threads = 10; + + if (debug_mode) PR_fprintf(output, + "%s: Using %d virtual processors, %d threads, limit = %d and %s threads\n", + programName, max_virtual_procs, threads, limit, + (thread_scope == RCThread::local) ? "LOCAL" : "GLOBAL"); + + for (virtual_procs = 0; virtual_procs < max_virtual_procs; ++virtual_procs) + { + if (debug_mode) + PR_fprintf(output, + "%s: Setting number of virtual processors to %d\n", + programName, virtual_procs + 1); + RCPrimordialThread::SetVirtualProcessors(virtual_procs + 1); + for (active = 0; active < threads; active++) + { + hammer[active] = new Hammer(thread_scope, &ml, &cv, limit); + hammer[active]->Start(); /* then make it roll */ + RCThread::Sleep(interleave); /* start them slowly */ + } + + /* + * The last thread started has had the opportunity to run for + * 'interleave' seconds. Now gather them all back in. + */ + { + RCEnter scope(&ml); + for (poll = 0; poll < threads; poll++) + { + if (hammer[poll]->action == HammerData::sg_go) /* don't overwrite done */ + hammer[poll]->action = HammerData::sg_stop; /* ask him to stop */ + } + } + + while (active > 0) + { + for (poll = 0; poll < threads; poll++) + { + ml.Acquire(); + while (hammer[poll]->action < HammerData::sg_done) cv.Wait(); + ml.Release(); + + if (hammer[poll]->problem == HammerData::sg_okay) + { + duration = RCInterval(RCInterval::now) - 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) PR_fprintf(output, + "%s: test failed %s after %ld seconds\n", + programName, where[hammer[poll]->problem], duration); + else failed_already=1; + } + active -= 1; /* this is another one down */ + (void)hammer[poll]->Join(); + hammer[poll] = NULL; + } + } + if (debug_mode) PR_fprintf(output, + "%s: [%ld [%ld] %ld] writes/sec average\n", + programName, writesMin, + writesTot * 1000 / durationTot, writesMax); + } + + failed_already |= (PR_FAILURE == RCPrimordialThread::Cleanup()); + PR_fprintf(output, "%s\n", (failed_already) ? "FAIL\n" : "PASS\n"); + return failed_already; +} /* main */ diff --git a/nsprpub/pr/src/cplus/tests/switch.cpp b/nsprpub/pr/src/cplus/tests/switch.cpp new file mode 100644 index 000000000..4cb14c48f --- /dev/null +++ b/nsprpub/pr/src/cplus/tests/switch.cpp @@ -0,0 +1,234 @@ +/* -*- 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.cpp +** Description: trying to time context switches +*/ + +#include "rccv.h" +#include "rcinrval.h" +#include "rclock.h" +#include "rcthread.h" + +#include <prio.h> +#include <prlog.h> +#include <prprf.h> +#include <plerror.h> +#include <plgetopt.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; + +class Home: public RCCondition +{ +public: + virtual ~Home(); + Home(Home *link, RCLock* ml); + +public: + Home *next; + RCLock* ml; + PRBool twiddle; +}; /* Home */ + +Home::~Home() { } + +Home::Home(Home *link, RCLock* lock): RCCondition(lock) +{ + ml = lock; + next = link; + twiddle = PR_FALSE; +} /* Home::Home */ + +class Shared: public Home, public RCThread +{ +public: + Shared(RCThread::Scope scope, Home* link, RCLock* ml); + +private: + ~Shared(); + void RootFunction(); +}; /* Shared */ + +Shared::Shared(RCThread::Scope scope, Home* link, RCLock* lock): + Home(link, lock), RCThread(scope, RCThread::joinable) { } + +Shared::~Shared() { } + +void Shared::RootFunction() +{ + PRStatus status = PR_SUCCESS; + while (PR_SUCCESS == status) + { + RCEnter entry(ml); + while (twiddle && (PR_SUCCESS == status)) status = Wait(); + if (verbosity) PR_fprintf(debug_out, "+"); + twiddle = PR_TRUE; + next->twiddle = PR_FALSE; + next->Notify(); + } +} /* Shared::RootFunction */ + +static void Help(void) +{ + debug_out = PR_STDOUT; + + PR_fprintf( + debug_out, "Usage: >./switch [-d] [-c n] [-t n] [-T n] [-G]\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 n\tglobal threads only (default: FALSE)\n"); + PR_fprintf(debug_out, "-C n\tconcurrency setting (default: 1)\n"); +} /* Help */ + +PRIntn main(PRIntn argc, char **argv) +{ + PLOptStatus os; + PRStatus status; + PRBool help = PR_FALSE; + PRUintn concurrency = 1; + RCThread::Scope thread_scope = RCThread::local; + 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 = RCThread::global; + 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"); + } + + /* + ** The interesting part starts here + */ + RCLock lock; + Shared* shared; + Home home(NULL, &lock); + Home* link = &home; + RCInterval timein, timeout = 0; + + /* Build up the string of objects */ + for (thread_count = 1; thread_count <= thread_limit; ++thread_count) + { + shared = new Shared(thread_scope, link, &lock); + shared->Start(); /* make it run */ + link = (Home*)shared; + } + + /* Pass the message around the horn a few times */ + for (loop_count = 1; loop_count <= loop_limit; ++loop_count) + { + timein.SetToNow(); + for (inner_count = 0; inner_count < INNER_LOOPS; ++inner_count) + { + RCEnter entry(&lock); + home.twiddle = PR_TRUE; + shared->twiddle = PR_FALSE; + shared->Notify(); + while (home.twiddle) + { + failed = (PR_FAILURE == home.Wait()) ? PR_TRUE : PR_FALSE; + } + } + timeout += (RCInterval(RCInterval::now) - timein); + } + + /* Figure out how well we did */ + if (debug_mode) + { + average = timeout.ToMicroseconds() + / (INNER_LOOPS * loop_limit * thread_count); + PR_fprintf( + debug_out, "Average switch times %d usecs for %d threads\n", + average, thread_limit); + } + + /* Start reclamation process */ + link = shared; + for (thread_count = 1; thread_count <= thread_limit; ++thread_count) + { + if (&home == link) break; + status = ((Shared*)link)->Interrupt(); + 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 = shared->Join(); + if (PR_SUCCESS != status) + { + failed = PR_TRUE; + if (debug_mode) + PL_FPrintError(debug_out, "Failed to join"); + } + if (&home == link) break; + shared = (Shared*)link; + } + + PR_fprintf(PR_STDOUT, ((failed) ? "FAILED\n" : "PASSED\n")); + + failed |= (PR_SUCCESS == RCPrimordialThread::Cleanup()); + + return ((failed) ? 1 : 0); +} /* main */ + +/* switch.c */ diff --git a/nsprpub/pr/src/cplus/tests/thread.cpp b/nsprpub/pr/src/cplus/tests/thread.cpp new file mode 100644 index 000000000..442c534d0 --- /dev/null +++ b/nsprpub/pr/src/cplus/tests/thread.cpp @@ -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/. */ + +/* thread.cpp - a test program */ + +#include "rcthread.h" + +#include <prlog.h> + +#include <stdio.h> + +class TestThread: public RCThread +{ +public: + TestThread(RCThread::State state, PRIntn count); + + virtual void RootFunction(); + +protected: + virtual ~TestThread(); + +private: + PRUint32 mydata; +}; + +TestThread::~TestThread() { } + +TestThread::TestThread(RCThread::State state, PRIntn count): + RCThread(RCThread::global, state, 0) { mydata = count; } + +void TestThread::RootFunction() +{ + SetPriority(RCThread::high); + printf("TestThread::RootFunction %d did it\n", mydata); +} /* TestThread::RootFunction */ + +class Foo1 +{ +public: + Foo1(); + virtual ~Foo1(); + + TestThread *thread; + PRIntn data; +}; + +Foo1::Foo1() +{ + data = 0xafaf; + thread = new TestThread(RCThread::joinable, 0xafaf); + thread->Start(); +} + +Foo1::~Foo1() +{ + PRStatus rv = thread->Join(); + PR_ASSERT(PR_SUCCESS == rv); +} /* Foo1::~Foo1 */ + +PRIntn main(PRIntn argc, char **agrv) +{ + PRStatus status; + PRIntn count = 100; + RCThread *thread[10]; + while (--count > 0) + { + TestThread *thread = new TestThread(RCThread::joinable, count); + status = thread->Start(); /* have to remember to start it */ + PR_ASSERT(PR_SUCCESS == status); + status = thread->Join(); /* this should work */ + PR_ASSERT(PR_SUCCESS == status); + } + while (++count < 100) + { + TestThread *thread = new TestThread(RCThread::unjoinable, count); + status = thread->Start(); /* have to remember to start it */ + PR_ASSERT(PR_SUCCESS == status); + } + + { + Foo1 *foo1 = new Foo1(); + PR_ASSERT(NULL != foo1); + delete foo1; + } + + { + for (count = 0; count < 10; ++count) + { + thread[count] = new TestThread( RCThread::joinable, count); + status = thread[count]->Start(); /* have to remember to start it */ + PR_ASSERT(PR_SUCCESS == status); + } + for (count = 0; count < 10; ++count) + { + PRStatus rv = thread[count]->Join(); + PR_ASSERT(PR_SUCCESS == rv); + } + } + + (void)RCPrimordialThread::Cleanup(); + + return 0; +} /* main */ + +/* thread.cpp */ + diff --git a/nsprpub/pr/src/cplus/tests/time.cpp b/nsprpub/pr/src/cplus/tests/time.cpp new file mode 100644 index 000000000..ad27caaac --- /dev/null +++ b/nsprpub/pr/src/cplus/tests/time.cpp @@ -0,0 +1,29 @@ +/* -*- 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/. */ + +/* time.cpp - a test program */ + +#include "rctime.h" + +#include <prlog.h> +#include <prprf.h> + +#define DEFAULT_ITERATIONS 100 + +PRIntn main(PRIntn argc, char **argv) +{ + RCTime unitialized; + RCTime now(PR_Now()); + RCTime current(RCTime::now); + PRTime time = current; + + unitialized = now; + now.Now(); + + return 0; +} /* main */ + +/* time.cpp */ + diff --git a/nsprpub/pr/src/cplus/tests/tpd.cpp b/nsprpub/pr/src/cplus/tests/tpd.cpp new file mode 100644 index 000000000..42290ab11 --- /dev/null +++ b/nsprpub/pr/src/cplus/tests/tpd.cpp @@ -0,0 +1,336 @@ +/* -*- 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.cpp +** Description: Exercising the thread private data bailywick. +*/ + +#include "prlog.h" +#include "prprf.h" +#include "rcthread.h" + +#include <string.h> + +#include "plgetopt.h" + +/* +** class MyThread +*/ +class MyThread: public RCThread +{ +public: + MyThread(); + +private: + ~MyThread(); + void RootFunction(); +}; /* MyThread */ + +/* +** class MyPrivateData +*/ +class MyPrivateData: public RCThreadPrivateData +{ +public: + virtual ~MyPrivateData(); + + MyPrivateData(); + MyPrivateData(char*); + MyPrivateData(const MyPrivateData&); + + void Release(); + +private: + char *string; +}; /* MyPrivateData */ + +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) + { + PR_fprintf( + fout, "@ line %d destructor should %shave been called and was%s\n", + line, ((should) ? "" : "NOT "), ((did) ? "" : " NOT")); + } +} /* 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__)) + +int main(PRIntn argc, char *argv[]) +{ + PRStatus rv; + PRUintn keys; + MyThread *thread; + const RCThreadPrivateData *pd; + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "d"); + RCThread *primordial = RCThread::WrapPrimordialThread(); + 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); + + fout = PR_STDOUT; + + MyPrivateData extension = MyPrivateData("EXTENSION"); + MyPrivateData 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 < 4; ++keys) + { + rv = RCThread::NewPrivateIndex(&key[keys]); + key[keys + 4] = key[keys] + 4; + MY_ASSERT(PR_SUCCESS == rv); + } + PrintProgress(__LINE__); + + /* the first four should be bu null, the last four undefined and null */ + did = should = PR_FALSE; + for (keys = 0; keys < 8; ++keys) + { + pd = RCThread::GetPrivateData(key[keys]); + MY_ASSERT(NULL == pd); + } + PrintProgress(__LINE__); + + /* initially set private data for new keys */ + did = should = PR_FALSE; + for (keys = 0; keys < 4; ++keys) + { + rv = RCThread::SetPrivateData(key[keys], &key_string[keys]); + MY_ASSERT(PR_SUCCESS == rv); + } + PrintProgress(__LINE__); + + /* re-assign the private data, albeit the same content */ + did = PR_FALSE; should = PR_TRUE; + for (keys = 0; keys < 4; ++keys) + { + pd = RCThread::GetPrivateData(key[keys]); + PR_ASSERT(NULL != pd); + rv = RCThread::SetPrivateData(key[keys], &key_string[keys]); + MY_ASSERT(PR_SUCCESS == rv); + } + PrintProgress(__LINE__); + + /* set private to <empty> */ + did = PR_FALSE; should = PR_TRUE; + for (keys = 0; keys < 4; ++keys) + { + rv = RCThread::SetPrivateData(key[keys]); + MY_ASSERT(PR_SUCCESS == rv); + } + PrintProgress(__LINE__); + + /* should all be null now */ + did = should = PR_FALSE; + for (keys = 0; keys < 4; ++keys) + { + pd = RCThread::GetPrivateData(key[keys]); + PR_ASSERT(NULL == pd); + } + PrintProgress(__LINE__); + + /* allocate another batch of keys and assign data to them */ + did = should = PR_FALSE; + for (keys = 8; keys < 127; ++keys) + { + rv = RCThread::NewPrivateIndex(&key[keys]); + MY_ASSERT(PR_SUCCESS == rv); + rv = RCThread::SetPrivateData(key[keys], &extension); + MY_ASSERT(PR_SUCCESS == rv); + } + PrintProgress(__LINE__); + + /* set all the extended slots to <empty> */ + did = PR_FALSE; should = PR_TRUE; + for (keys = 8; keys < 127; ++keys) + { + rv = RCThread::SetPrivateData(key[keys]); + MY_ASSERT(PR_SUCCESS == rv); + } + PrintProgress(__LINE__); + + /* set all the extended slots to <empty> again (noop) */ + did = should = PR_FALSE; + for (keys = 8; keys < 127; ++keys) + { + rv = RCThread::SetPrivateData(key[keys]); + MY_ASSERT(PR_SUCCESS == rv); + } + + if (debug) PR_fprintf(fout, "Creating thread\n"); + thread = new MyThread(); + if (debug) PR_fprintf(fout, "Starting thread\n"); + thread->Start(); + if (debug) PR_fprintf(fout, "Joining thread\n"); + (void)thread->Join(); + if (debug) PR_fprintf(fout, "Joined thread\n"); + + failed |= (PR_FAILURE == RCPrimordialThread::Cleanup()); + + (void)PR_fprintf( + fout, "%s\n",((PR_TRUE == failed) ? "FAILED" : "PASSED")); + + return (failed) ? 1 : 0; + +} /* main */ + +/* +** class MyPrivateData +*/ +MyPrivateData::~MyPrivateData() +{ + PR_fprintf( + fout, "MyPrivateData::~MyPrivateData[%s]\n", + (NULL != string) ? string : "NULL"); +} /* MyPrivateData::~MyPrivateData */ + +MyPrivateData::MyPrivateData(): RCThreadPrivateData() +{ + PR_fprintf(fout, "MyPrivateData::MyPrivateData()\n"); + string = NULL; +} /* MyPrivateData::MyPrivateData */ + +MyPrivateData::MyPrivateData(char* data): RCThreadPrivateData() +{ + PR_fprintf(fout, "MyPrivateData::MyPrivateData(char* data)\n"); + string = data; +} /* MyPrivateData:: MyPrivateData */ + +MyPrivateData::MyPrivateData(const MyPrivateData& him): RCThreadPrivateData(him) +{ + PR_fprintf(fout, "MyPrivateData::MyPrivateData(const MyPrivateData& him)\n"); + string = him.string; +} /* MyPrivateData:: MyPrivateData */ + +void MyPrivateData::Release() +{ + if (should) did = PR_TRUE; + else failed = PR_TRUE; +} /* MyPrivateData::operator= */ + +/* +** class MyThread +*/ +MyThread::~MyThread() { } +MyThread::MyThread(): RCThread(RCThread::global, RCThread::joinable) { } + + +void MyThread::RootFunction() +{ + PRStatus rv; + PRUintn keys; + const RCThreadPrivateData *pd; + + MyPrivateData extension = MyPrivateData("EXTENSION"); + MyPrivateData 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 = GetPrivateData(key[keys]); + MY_ASSERT(NULL == pd); + } + PrintProgress(__LINE__); + + did = should = PR_FALSE; + for (keys = 0; keys < 4; ++keys) + { + rv = SetPrivateData(keys, &key_string[keys]); + MY_ASSERT(PR_SUCCESS == rv); + } + PrintProgress(__LINE__); + +#if !defined(DEBUG) + did = should = PR_FALSE; + for (keys = 4; keys < 8; ++keys) + { + rv = SetPrivateData(keys, &key_string[keys]); + MY_ASSERT(PR_FAILURE == rv); + } + PrintProgress(__LINE__); +#endif + + did = PR_FALSE; should = PR_TRUE; + for (keys = 0; keys < 4; ++keys) + { + rv = SetPrivateData(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 = SetPrivateData(key[keys]); + MY_ASSERT(PR_SUCCESS == rv); + } + PrintProgress(__LINE__); + + did = should = PR_FALSE; + for (keys = 0; keys < 4; ++keys) + { + rv = SetPrivateData(key[keys]); + MY_ASSERT(PR_SUCCESS == rv); + } + PrintProgress(__LINE__); + + did = should = PR_FALSE; + for (keys = 8; keys < 127; ++keys) + { + rv = SetPrivateData(key[keys], &extension); + MY_ASSERT(PR_SUCCESS == rv); + } + PrintProgress(__LINE__); + + did = PR_FALSE; should = PR_TRUE; + for (keys = 8; keys < 127; ++keys) + { + rv = SetPrivateData(key[keys]); + MY_ASSERT(PR_SUCCESS == rv); + } + PrintProgress(__LINE__); + + did = should = PR_FALSE; + for (keys = 8; keys < 127; ++keys) + { + rv = SetPrivateData(key[keys]); + MY_ASSERT(PR_SUCCESS == rv); + } +} /* MyThread::RootFunction */ + +/* tpd.c */ |