diff options
Diffstat (limited to 'pr/tests')
42 files changed, 4377 insertions, 716 deletions
diff --git a/pr/tests/Makefile b/pr/tests/Makefile index 9db675f9..d1fc8afd 100644 --- a/pr/tests/Makefile +++ b/pr/tests/Makefile @@ -37,6 +37,7 @@ OS_CFLAGS = $(OS_EXE_CFLAGS) endif CSRCS = \ + acceptread.c \ accept.c \ alarm.c \ atomic.c \ @@ -52,11 +53,14 @@ CSRCS = \ dtoa.c \ exit.c \ fileio.c \ + foreign.c \ forktest.c \ fsync.c \ getproto.c \ i2l.c \ + initclk.c \ inrval.c \ + instrumt.c \ intrupt.c \ io_timeout.c \ ipv6.c \ @@ -86,9 +90,11 @@ CSRCS = \ poll_er.c \ poll_nm.c \ poll_to.c \ + pollable.c \ prftest1.c \ prftest2.c \ priotest.c \ + provider.c \ ranfile.c \ sel_spd.c \ selct_er.c \ @@ -106,6 +112,7 @@ CSRCS = \ sprintf.c \ sproc_ch.c \ sproc_p.c \ + stack.c \ stdio.c \ strod.c \ suspend.c \ @@ -120,6 +127,7 @@ CSRCS = \ tmoacc.c \ tmocon.c \ tpd.c \ + version.c \ udpsrv.c \ writev.c \ xnotify.c \ @@ -133,7 +141,7 @@ endif PROGS = $(addprefix $(OBJDIR)/, $(CSRCS:.c=$(PROG_SUFFIX))) -TARGETS = $(PROGS) $(OBJS) +TARGETS = $(PROGS) INCLUDES = -I$(DIST)/include/obsolete -I$(DIST)/include/private -I$(DIST)/include @@ -165,96 +173,112 @@ PWD = $(shell pwd) endif ifeq ($(OS_ARCH), IRIX) -LDOPTS += -rpath $(PWD)/$(DIST)/lib -rdata_shared - + ifeq ($(USE_CPLUS), 1) + CC = CC + endif + LDOPTS += -rpath $(PWD)/$(DIST)/lib -rdata_shared # For 6.x machines, include this flag -ifeq ($(basename $(OS_RELEASE)),6) -ifeq ($(USE_N32),1) -LDOPTS += -n32 -else -LDOPTS += -32 -endif -endif + 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 ifeq ($(OS_ARCH), OSF1) + ifeq ($(USE_CPLUS), 1) + CC = cxx + endif # I haven't figured out how to pass -rpath to cc on OSF1 V3.2, so # we do static linking. -ifeq ($(OS_RELEASE), V3.2) - LIBPR = $(DIST)/lib/libnspr$(MOD_VERSION).a - LIBPLC = $(DIST)/lib/libplc$(MOD_VERSION).a - EXTRA_LIBS = -lc_r -else - LDOPTS += -rpath $(PWD)/$(DIST)/lib -endif + ifeq ($(OS_RELEASE), V3.2) + LIBPR = $(DIST)/lib/libnspr$(MOD_VERSION).a + LIBPLC = $(DIST)/lib/libplc$(MOD_VERSION).a + EXTRA_LIBS = -lc_r + else + LDOPTS += -rpath $(PWD)/$(DIST)/lib + endif endif ifeq ($(OS_ARCH), HP-UX) -LDOPTS += -Wl,+s,+b,$(PWD)/$(DIST)/lib + LDOPTS += -z -Wl,+s,+b,$(PWD)/$(DIST)/lib + ifeq ($(USE_64),1) + LDOPTS += -L/usr/lib/pa20_64 -lpthread +DD64 + endif endif # AIX ifeq ($(OS_ARCH),AIX) -ifeq ($(CLASSIC_NSPR),1) -LDOPTS += -blibpath:.:$(PWD)/$(DIST)/lib:/usr/lpp/xlC/lib:/usr/lib:/lib -else -LDOPTS += -blibpath:.:$(PWD)/$(DIST)/lib:/usr/lib/threads:/usr/lpp/xlC/lib:/usr/lib:/lib -endif -ifeq ($(OS_ARCH)$(OS_RELEASE),AIX4.1) -LIBPR = -lnspr$(MOD_VERSION)_shr -LIBPLC = -lplc$(MOD_VERSION)_shr -else -LDOPTS += -brtl -EXTRA_LIBS = -ldl -endif + ifeq ($(CLASSIC_NSPR),1) + LDOPTS += -blibpath:.:$(PWD)/$(DIST)/lib:/usr/lpp/xlC/lib:/usr/lib:/lib + else + LDOPTS += -blibpath:.:$(PWD)/$(DIST)/lib:/usr/lib/threads:/usr/lpp/xlC/lib:/usr/lib:/lib + endif + ifeq ($(OS_ARCH)$(OS_RELEASE),AIX4.1) + LIBPR = -lnspr$(MOD_VERSION)_shr + LIBPLC = -lplc$(MOD_VERSION)_shr + else + LDOPTS += -brtl + EXTRA_LIBS = -ldl + endif endif # Solaris ifeq ($(OS_ARCH), SunOS) -ifneq ($(OS_RELEASE), 4.1.3_U1) -ifdef NS_USE_GCC -LDOPTS += -Xlinker -R -Xlinker $(PWD)/$(DIST)/lib -else -LDOPTS += -R $(PWD)/$(DIST)/lib -endif -endif - -ifneq ($(LOCAL_THREADS_ONLY),1) + ifneq ($(OS_RELEASE), 4.1.3_U1) + ifdef NS_USE_GCC + LDOPTS += -Xlinker -R -Xlinker $(PWD)/$(DIST)/lib + else + ifeq ($(USE_CPLUS), 1) + CC = CC + endif + LDOPTS += -R $(PWD)/$(DIST)/lib + endif + endif + + ifneq ($(LOCAL_THREADS_ONLY),1) # SunOS 5.4 and 5.5 need to link with -lthread or -lpthread, # even though we already linked with these system libraries # when we built libnspr.so. -ifeq ($(OS_RELEASE), 5.4) -EXTRA_LIBS = -lthread -endif - -ifeq ($(OS_RELEASE), 5.5) -ifdef USE_PTHREADS -EXTRA_LIBS = -lpthread -else -EXTRA_LIBS = -lthread -endif -endif -endif # LOCAL_THREADS_ONLY + ifeq ($(OS_RELEASE), 5.4) + EXTRA_LIBS = -lthread + endif + + ifeq ($(OS_RELEASE), 5.5) + ifdef USE_PTHREADS + EXTRA_LIBS = -lpthread + else + EXTRA_LIBS = -lthread + endif + endif + endif # LOCAL_THREADS_ONLY endif # SunOS ifeq ($(OS_ARCH), NEC) -EXTRA_LIBS = $(OS_LIBS) + EXTRA_LIBS = $(OS_LIBS) # 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)/lib + export LD_RUN_PATH = $(PWD)/$(DIST)/lib endif ifeq ($(OS_ARCH), NCR) # NCR needs to link against -lsocket -lnsl -ldl (and -lc, which is # linked implicitly by $(CC)). Note that we did not link with these # system libraries when we built libnspr.so. -EXTRA_LIBS = -lsocket -lnsl -ldl + EXTRA_LIBS = -lsocket -lnsl -ldl # 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)/lib + export LD_RUN_PATH = $(PWD)/$(DIST)/lib endif ifeq ($(OS_ARCH), NEWS-OS) @@ -262,20 +286,20 @@ ifeq ($(OS_ARCH), NEWS-OS) # libnspr.so etc. at program startup. Equivalent to the -R or -rpath # option for ld on other platforms. #export LD_RUN_PATH = $(PWD)/$(DIST)/lib - LIBPR = $(DIST)/lib/libnspr$(MOD_VERSION).a - LIBPLC = $(DIST)/lib/libplc$(MOD_VERSION).a - EXTRA_LIBS = -lsocket -lnsl -lgen -lresolv + LIBPR = $(DIST)/lib/libnspr$(MOD_VERSION).a + LIBPLC = $(DIST)/lib/libplc$(MOD_VERSION).a + EXTRA_LIBS = -lsocket -lnsl -lgen -lresolv endif ifeq ($(OS_ARCH), Linux) -ifeq ($(OS_RELEASE), 1.2) -EXTRA_LIBS = -ldl -else -LDOPTS += -Xlinker -rpath $(PWD)/$(DIST)/lib -ifeq ($(USE_PTHREADS),1) -EXTRA_LIBS = -lpthread -endif -endif + ifeq ($(OS_RELEASE), 1.2) + EXTRA_LIBS = -ldl + else + LDOPTS += -Xlinker -rpath $(PWD)/$(DIST)/lib + ifeq ($(USE_PTHREADS),1) + EXTRA_LIBS = -lpthread + endif + endif endif ifeq ($(OS_ARCH), SCOOS) @@ -304,12 +328,29 @@ ifeq ($(OS_ARCH),FreeBSD) ifeq ($(USE_PTHREADS),1) EXTRA_LIBS = -lc_r endif +LDOPTS += -Xlinker -R $(PWD)/$(DIST)/lib endif ifeq ($(OS_ARCH),BSD_OS) EXTRA_LIBS = -ldl endif +ifeq ($(USE_PTHREADS),1) +ifeq ($(OS_ARCH),AIX) +LIBPTHREAD = -lpthreads +else + ifeq ($(OS_ARCH),FreeBSD) + LIBPTHREAD = -lc_r + else + ifeq ($(OS_ARCH)$(basename $(OS_RELEASE)),HP-UXB.10) + LIBPTHREAD = -ldce + else + LIBPTHREAD = -lpthread + endif + endif +endif +endif + ##################################################### # # The rules @@ -352,15 +393,7 @@ else ifeq ($(USE_PTHREADS), 1) $(OBJDIR)/attach: $(OBJDIR)/attach.$(OBJ_SUFFIX) @$(MAKE_OBJDIR) -ifeq ($(OS_ARCH), AIX) - $(CC) $< $(LDOPTS) $(LIBPLC) $(LIBPR) -lpthreads -o $@ -else -ifeq ($(OS_ARCH),FreeBSD) - $(CC) $< $(LDOPTS) $(LIBPLC) $(LIBPR) -lc_r -o $@ -else - $(CC) $< $(LDOPTS) $(LIBPLC) $(LIBPR) -lpthread -o $@ -endif -endif + $(CC) $< $(LDOPTS) $(LIBPLC) $(LIBPR) $(LIBPTHREAD) -o $@ endif @@ -400,6 +433,13 @@ install:: export clean:: rm -f $(TARGETS) +ifeq ($(USE_PTHREADS), 1) +$(OBJDIR)/foreign: $(OBJDIR)/foreign.o + $(CC) $(XCFLAGS) $< $(LDOPTS) $(LIBPLC) $(LIBPR) $(EXTRA_LIBS) $(LIBPTHREAD) -o $@ +$(OBJDIR)/provider: $(OBJDIR)/provider.o + $(CC) $(XCFLAGS) $< $(LDOPTS) $(LIBPLC) $(LIBPR) $(EXTRA_LIBS) $(LIBPTHREAD) -o $@ +endif + # # Run the test programs with no arguments # diff --git a/pr/tests/accept.c b/pr/tests/accept.c index 79ab811f..5318de74 100644 --- a/pr/tests/accept.c +++ b/pr/tests/accept.c @@ -48,12 +48,6 @@ #include "plgetopt.h" #include "plerror.h" -#ifdef XP_MAC -#include "prlog.h" -#define printf PR_LogPrint -extern void SetupMacPrintfLog(char *logFile); -#endif - #define BASE_PORT 8001 #define CLIENT_DATA 128 @@ -76,6 +70,7 @@ extern void SetupMacPrintfLog(char *logFile); PRIntervalTime timeoutTime; static PRInt32 count = 1; +static PRFileDesc *output; static PRNetAddr serverAddr; static PRThreadScope thread_scope = PR_LOCAL_THREAD; @@ -86,13 +81,8 @@ void Test_Assert(const char *msg, const char *file, PRIntn line) { failed_already=1; if (debug_mode) { -#if defined(WIN16) - printf( "@%s:%d ", file, line); - printf(msg); -#else - PR_fprintf(PR_STDERR, "@%s:%d ", file, line); - PL_FPrintError(PR_STDERR, msg); -#endif + PR_fprintf(output, "@%s:%d ", file, line); + PR_fprintf(output, msg); } } /* Test_Assert */ @@ -106,7 +96,7 @@ void timeout_callback(void *magic) { TEST_ASSERT(magic == (void *)CALLBACK_MAGIC); if (debug_mode) - printf("timeout callback called okay\n"); + PR_fprintf(output, "timeout callback called okay\n"); } #endif @@ -131,7 +121,7 @@ ClientThread(void *_action) if (!debug_mode) failed_already=1; else - printf("client: unable to create socket\n"); + PR_fprintf(output, "client: unable to create socket\n"); return; } @@ -142,10 +132,9 @@ ClientThread(void *_action) if (!debug_mode) failed_already=1; else - printf( + PR_fprintf(output, "client: unable to connect to server (%ld, %ld, %ld, %ld)\n", - iterations, rv, PR_GetError(), - PR_GetOSError()); + iterations, rv, PR_GetError(), PR_GetOSError()); goto ErrorExit; } @@ -155,25 +144,24 @@ ClientThread(void *_action) if (!debug_mode) failed_already=1; else - printf("client: unable to send to server (%d, %ld, %ld)\n", - CLIENT_DATA, rv, - PR_GetError()); + 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)); + PR_Sleep(PR_SecondsToInterval(TIMEOUTSECS + 1)); } } else { - PR_Sleep(PR_SecondsToInterval(TIMEOUTSECS+ - 1)); + PR_Sleep(PR_SecondsToInterval(TIMEOUTSECS + 1)); } if (debug_mode) - printf("."); + PR_fprintf(output, "."); PR_Close(sock); + sock = NULL; } if (debug_mode) - printf("\n"); + PR_fprintf(output, "\n"); ErrorExit: if (sock != NULL) @@ -203,7 +191,7 @@ RunTest(PRInt32 acceptType, PRInt32 clientAction) if (!listenSock) { failed_already=1; if (debug_mode) - printf("unable to create listen socket\n"); + PR_fprintf(output, "unable to create listen socket\n"); return; } listenAddr.inet.family = PR_AF_INET; @@ -213,7 +201,7 @@ RunTest(PRInt32 acceptType, PRInt32 clientAction) if (rv == PR_FAILURE) { failed_already=1; if (debug_mode) - printf("unable to bind\n"); + PR_fprintf(output, "unable to bind\n"); return; } @@ -221,7 +209,7 @@ RunTest(PRInt32 acceptType, PRInt32 clientAction) if (rv == PR_FAILURE) { failed_already=1; if (debug_mode) - printf("unable to listen\n"); + PR_fprintf(output, "unable to listen\n"); return; } @@ -232,7 +220,7 @@ RunTest(PRInt32 acceptType, PRInt32 clientAction) if (!clientThread) { failed_already=1; if (debug_mode) - printf("error creating client thread\n"); + PR_fprintf(output, "error creating client thread\n"); return; } @@ -288,8 +276,7 @@ RunTest(PRInt32 acceptType, PRInt32 clientAction) case CLIENT_TIMEOUT_ACCEPT: TEST_ASSERT(clientSock == 0); if (debug_mode) - printf("PR_GetError is %ld\n", - PR_GetError()); + PR_fprintf(output, "PR_GetError is %ld\n", PR_GetError()); TEST_ASSERT(PR_GetError() == PR_IO_TIMEOUT_ERROR); break; case CLIENT_NORMAL: @@ -342,8 +329,7 @@ RunTest(PRInt32 acceptType, PRInt32 clientAction) break; case CLIENT_TIMEOUT_SEND: if (debug_mode) - printf("clientSock = 0x%8.8lx\n", - clientSock); + PR_fprintf(output, "clientSock = 0x%8.8lx\n", clientSock); TEST_ASSERT(clientSock); TEST_ASSERT(status == -1); TEST_ASSERT(PR_GetError() == PR_IO_TIMEOUT_ERROR); @@ -431,7 +417,7 @@ static void Measure(void (*func)(void), const char *msg) d = (double)PR_IntervalToMicroseconds(stop - start); if (debug_mode) - printf("%40s: %6.2f usec\n", msg, d / count); + PR_fprintf(output, "%40s: %6.2f usec\n", msg, d / count); } @@ -467,6 +453,7 @@ int main(int argc, char **argv) PL_DestroyOptState(opt); PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + output = PR_STDERR; PR_STDIO_INIT(); #ifdef XP_MAC @@ -476,7 +463,7 @@ int main(int argc, char **argv) timeoutTime = PR_SecondsToInterval(TIMEOUTSECS); if (debug_mode) - printf("\nRun accept() sucessful connection tests\n"); + PR_fprintf(output, "\nRun accept() sucessful connection tests\n"); Measure(AcceptUpdatedTest, "PR_Accept()"); Measure(AcceptReadTest, "PR_AcceptRead()"); @@ -486,28 +473,19 @@ int main(int argc, char **argv) Measure(AcceptReadCallbackTest, "PR_NTFast_AcceptRead_WithTimeoutCallback()"); #endif if (debug_mode) - printf("\nRun accept() timeout in the accept tests\n"); + 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) - printf("\nRun accept() timeout in the read tests\n"); + 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 - if(failed_already) - { - printf("FAIL\n"); - return 1; - } - else - { - printf("PASS\n"); - return 0; - - } + PR_fprintf(output, "%s\n", (failed_already) ? "FAIL" : "PASS"); + return failed_already; } diff --git a/pr/tests/atomic.c b/pr/tests/atomic.c index d5e334d5..a2ba2044 100644 --- a/pr/tests/atomic.c +++ b/pr/tests/atomic.c @@ -22,7 +22,7 @@ PRIntn main(PRIntn argc, char **argv) { - PRInt32 rv, test, result = 0; + PRInt32 rv, oldval, test, result = 0; PRFileDesc *output = PR_GetSpecialFD(PR_StandardOutput); test = -2; @@ -42,6 +42,25 @@ PRIntn main(PRIntn argc, char **argv) output, "PR_AtomicIncrement(%d) == %d: %s\n", test, rv, (rv > 0) ? "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"); + test = 2; rv = PR_AtomicDecrement(&test); result = result | ((rv > 0) ? 0 : 1); diff --git a/pr/tests/attach.c b/pr/tests/attach.c index 3fa38d49..79a5d3d8 100644 --- a/pr/tests/attach.c +++ b/pr/tests/attach.c @@ -66,7 +66,7 @@ #include <os2.h> #endif -#define DEFAULT_COUNT 10000 +#define DEFAULT_COUNT 1000 PRIntn failed_already=0; PRIntn debug_mode; @@ -81,21 +81,17 @@ AttachDetach(void) 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: " - "nspr20 error code %d, os error code %d\n", - count, PR_GetError(), PR_GetOSError()); - failed_already = 1; - return; + fprintf(stderr, "Error attaching thread %d: PR_AttachThread failed\n", + count); + failed_already = 1; + return; } - PR_DetachThread(); - } } @@ -277,7 +273,7 @@ int main(int argc, char **argv) } rv = WaitForSingleObject(hThread, INFINITE); if (debug_mode)PR_ASSERT(rv != WAIT_FAILED); - else if (rv != WAIT_FAILED) { + else if (rv == WAIT_FAILED) { failed_already=1; goto exit_now; } @@ -296,6 +292,7 @@ int main(int argc, char **argv) else { if (debug_mode) printf ("thread creation succeeded \n"); + sleep(3); goto exit_now; } rv = waitpid(threadID, NULL, 0); diff --git a/pr/tests/bigfile.c b/pr/tests/bigfile.c index 9cb4e7fd..399da8cd 100644 --- a/pr/tests/bigfile.c +++ b/pr/tests/bigfile.c @@ -35,10 +35,10 @@ static void Verbose(Verbosity, const char*, const char*, PRIntn); #define VERBOSE(_l, _m) Verbose(_l, _m, __FILE__, __LINE__) -static PRIntn filesize = 1; static PRIntn test_result = 2; static PRFileDesc *output = NULL; static PRIntn verbose = v_silent; +static PRIntn filesize = DEFAULT_FILESIZE; static PRIntn Usage(void) { @@ -46,6 +46,7 @@ static PRIntn Usage(void) 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 */ @@ -64,6 +65,7 @@ static PRStatus DeleteIfFound(const char *filename) } else if (PR_FILE_NOT_FOUND_ERROR != PR_GetError()) VERBOSE(v_shout, "Cannot access big file"); + else rv = PR_SUCCESS; return rv; } /* DeleteIfFound */ @@ -87,20 +89,43 @@ static void 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 */ + PRIntn main(PRIntn 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; - PRFileInfo64 *big_info = NULL; - PRInt64 big_answer, big_size, one_meg, zero_meg, big_fragment; - PRInt64 filesize64; + PRInt64 filesize64, big_answer, big_size, one_meg, zero_meg, big_fragment; + PRInt64 sevenFox = LL_INIT(0,0x7fffffff); - PLOptState *opt = PL_CreateOptState(argc, argv, "dvhs:"); + PLOptState *opt = PL_CreateOptState(argc, argv, "dtvhs:"); output = PR_GetSpecialFD(PR_StandardError); PR_STDIO_INIT(); @@ -116,6 +141,9 @@ PRIntn main(PRIntn argc, char **argv) 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; @@ -132,9 +160,13 @@ PRIntn main(PRIntn argc, char **argv) } PL_DestroyOptState(opt); - if (NULL == filename) return Usage(); if (0 == count) count = DEFAULT_COUNT; if (0 == filesize) filesize = DEFAULT_FILESIZE; + if (NULL == filename) + { + if (DEFAULT_FILESIZE != filesize) return Usage(); + else filename = "/usr/tmp/bigfile.dat"; + } if (PR_FAILURE == DeleteIfFound(filename)) return 1; @@ -145,7 +177,7 @@ PRIntn main(PRIntn argc, char **argv) LL_I2L(filesize64, filesize); buffer = (char*)PR_MALLOC(BUFFER_SIZE); LL_I2L(big_fragment, BUFFER_SIZE); - LL_MUL(big_size, filesize64, one_meg); + LL_MUL(filesize64, filesize64, one_meg); for (loop = 0; loop < BUFFER_SIZE; ++loop) buffer[loop] = (char)loop; @@ -157,32 +189,45 @@ PRIntn main(PRIntn argc, char **argv) big_answer = file->methods->available64(file); if (!LL_IS_ZERO(big_answer)) return Error("empty available64()", filename); -#if 0 - VERBOSE(v_whisper, "Filling big file with data"); - while (LL_CMP(big_answer, <, big_size)) - { - bytes = file->methods->write(file, buffer, BUFFER_SIZE); - if (bytes != BUFFER_SIZE) return Error("write", filename); - LL_ADD(big_answer, big_answer, big_fragment); - } -#else - LL_SUB(big_size, big_size, one_meg); + LL_SUB(big_size, filesize64, one_meg); + VERBOSE(v_whisper, "Creating sparce 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 sparce file"); bytes = file->methods->write(file, buffer, BUFFER_SIZE); if (bytes != BUFFER_SIZE) return Error("write", filename); -#endif - VERBOSE(v_whisper, "Testing available space in filled file"); + VERBOSE(v_whisper, "Testing available space at end of sparce file"); big_answer = file->methods->available64(file); - if (LL_NE(big_answer, zero_meg)) return Error("eof available64()", filename); + if (!LL_IS_ZERO(big_answer)) return Error("eof available64()", filename); + + VERBOSE(v_whisper, "Getting big info on sparce 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 sparce 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_NE(big_answer, zero_meg)) return Error("rewind seek64()", filename); + if (!LL_IS_ZERO(big_answer)) return Error("rewind seek64()", filename); VERBOSE(v_whisper, "Establishing available space in rewound file"); - big_size = file->methods->available64(file); - if (!LL_GE_ZERO(big_size)) return Error("bof available64()", filename); + 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); @@ -190,47 +235,59 @@ PRIntn main(PRIntn argc, char **argv) VERBOSE(v_whisper, "Reopening big file"); file = PR_Open(filename, PR_RDWR, 0666); - if (NULL == file) return Error("bof seek64()", filename); + 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(big_size, big_answer)) return Error("reopened available64()", filename); + if (LL_NE(filesize64, big_answer)) + return Error("reopened available64()", filename); big_answer = zero_meg; - VERBOSE(v_whisper, "Rewriting big file data"); - while (LL_CMP(big_answer, <, big_size)) + 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); + 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_NE(big_answer, zero_meg)) return Error("eof available64()", filename); + if (!LL_IS_ZERO(big_answer)) + return Error("eof available64()", filename); - VERBOSE(v_whisper, "Rewinding full file file"); + VERBOSE(v_whisper, "Rewinding full file"); big_answer = file->methods->seek64(file, zero_meg, PR_SEEK_SET); - if (LL_NE(big_answer, zero_meg)) return Error("bof seek64()", filename); + 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, big_size)) return Error("bof available64()", filename); + 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, big_size, PR_SEEK_SET); - if (LL_NE(big_answer, big_size)) return Error("eof seek64()", filename); + 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"); - big_info = PR_NEWZAP(PRFileInfo64); - rv = file->methods->fileInfo64(file, big_info); + 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); - PR_DELETE(big_info); + 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); diff --git a/pr/tests/cltsrv.c b/pr/tests/cltsrv.c index 346ff2f9..f3333be4 100644 --- a/pr/tests/cltsrv.c +++ b/pr/tests/cltsrv.c @@ -79,6 +79,8 @@ #define RECV_FLAGS 0 #define SEND_FLAGS 0 +#define DEFAULT_LOW 0 +#define DEFAULT_HIGH 0 #define BUFFER_SIZE 1024 #define DEFAULT_BACKLOG 5 #define DEFAULT_PORT 12848 @@ -204,22 +206,6 @@ static PRBool Aborted(PRStatus rv) PR_TRUE : PR_FALSE; } -static void Assert(const char *s, const char *file, PRIntn ln) -{ - PRIntn error = PR_GetError(), syserrno = PR_GetOSError(); - TEST_LOG( - cltsrv_log_file, TEST_LOG_ALWAYS, - ("Assertion failed(0x%lx): '%s' in %s[%d]\n", - PR_CurrentThread(), s, file, ln)); - TEST_LOG( - cltsrv_log_file, TEST_LOG_ALWAYS, - ("**Error information: Error = %d, OSError = %d\n", - error, syserrno)); - PR_LogFlush(); - - PR_Abort(); -} /* Assert */ - static void TimeOfDayMessage(const char *msg, PRThread* me) { char buffer[100]; @@ -229,7 +215,7 @@ static void TimeOfDayMessage(const char *msg, PRThread* me) TEST_LOG( cltsrv_log_file, TEST_LOG_ALWAYS, - ("%s(0x%lx): %s\n", msg, me, buffer)); + ("%s(0x%p): %s\n", msg, me, buffer)); } /* TimeOfDayMessage */ @@ -264,7 +250,7 @@ static void PR_CALLBACK Client(void *arg) (void)PR_NetAddrToString(&client->serverAddress, buffer, sizeof(buffer)); TEST_LOG(cltsrv_log_file, TEST_LOG_INFO, - ("\tClient(0x%lx): connecting to server at %s\n", me, buffer)); + ("\tClient(0x%p): connecting to server at %s\n", me, buffer)); fd = PR_Socket(domain, SOCK_STREAM, protocol); TEST_ASSERT(NULL != fd); @@ -273,7 +259,7 @@ static void PR_CALLBACK Client(void *arg) { TEST_LOG( cltsrv_log_file, TEST_LOG_ERROR, - ("\tClient(0x%lx): conection failed\n", me)); + ("\tClient(0x%p): conection failed\n", me)); goto aborted; } @@ -281,10 +267,10 @@ static void PR_CALLBACK Client(void *arg) descriptor->size = PR_htonl(descbytes = rand() % clipping); PR_snprintf( descriptor->filename, sizeof(descriptor->filename), - "CS%lx%lx-%lx.dat", client->started, me, client->operations); + "CS%p%p-%p.dat", client->started, me, client->operations); TEST_LOG( cltsrv_log_file, TEST_LOG_VERBOSE, - ("\tClient(0x%lx): sending descriptor for %ld bytes\n", me, descbytes)); + ("\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) @@ -294,7 +280,7 @@ static void PR_CALLBACK Client(void *arg) { TEST_LOG( cltsrv_log_file, TEST_LOG_ERROR, - ("\tClient(0x%lx): send descriptor timeout\n", me)); + ("\tClient(0x%p): send descriptor timeout\n", me)); goto retry; } } @@ -308,7 +294,7 @@ static void PR_CALLBACK Client(void *arg) filebytes = descbytes - netbytes; TEST_LOG( cltsrv_log_file, TEST_LOG_VERBOSE, - ("\tClient(0x%lx): sending %d bytes\n", me, filebytes)); + ("\tClient(0x%p): sending %d bytes\n", me, filebytes)); bytes = PR_Send(fd, buffer, filebytes, SEND_FLAGS, timeout); if (filebytes != bytes) { @@ -317,7 +303,7 @@ static void PR_CALLBACK Client(void *arg) { TEST_LOG( cltsrv_log_file, TEST_LOG_ERROR, - ("\tClient(0x%lx): send data timeout\n", me)); + ("\tClient(0x%p): send data timeout\n", me)); goto retry; } } @@ -332,7 +318,7 @@ static void PR_CALLBACK Client(void *arg) netbytes = descbytes - filebytes; TEST_LOG( cltsrv_log_file, TEST_LOG_VERBOSE, - ("\tClient(0x%lx): receiving %d bytes\n", me, netbytes)); + ("\tClient(0x%p): receiving %d bytes\n", me, netbytes)); bytes = PR_Recv(fd, buffer, netbytes, RECV_FLAGS, timeout); if (-1 == bytes) { @@ -340,17 +326,17 @@ static void PR_CALLBACK Client(void *arg) { TEST_LOG( cltsrv_log_file, TEST_LOG_ERROR, - ("\tClient(0x%lx): receive data aborted\n", me)); + ("\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%lx): receive data timeout\n", me)); + ("\tClient(0x%p): receive data timeout\n", me)); else TEST_LOG( cltsrv_log_file, TEST_LOG_ERROR, - ("\tClient(0x%lx): receive error (%ld, %ld)\n", + ("\tClient(0x%p): receive error (%d, %d)\n", me, PR_GetError(), PR_GetOSError())); goto retry; } @@ -358,7 +344,7 @@ static void PR_CALLBACK Client(void *arg) { TEST_LOG( cltsrv_log_file, TEST_LOG_ERROR, - ("\t\tClient(0x%lx): unexpected end of stream\n", + ("\t\tClient(0x%p): unexpected end of stream\n", PR_CurrentThread())); break; } @@ -372,7 +358,7 @@ retry: (void)PR_Close(fd); fd = NULL; TEST_LOG( cltsrv_log_file, TEST_LOG_INFO, - ("\tClient(0x%lx): disconnected from server\n", me)); + ("\tClient(0x%p): disconnected from server\n", me)); PR_Lock(client->ml); client->operations += 1; @@ -395,7 +381,7 @@ aborted: PR_DELETE(descriptor); TEST_LOG( cltsrv_log_file, TEST_LOG_ALWAYS, - ("\tClient(0x%lx): stopped after %lu operations and %lu bytes\n", + ("\tClient(0x%p): stopped after %u operations and %u bytes\n", PR_CurrentThread(), client->operations, client->bytesTransferred)); } /* Client */ @@ -412,7 +398,7 @@ static PRStatus ProcessRequest(PRFileDesc *fd, CSServer_t *server) TEST_LOG( cltsrv_log_file, TEST_LOG_VERBOSE, - ("\tProcessRequest(0x%lx): receiving desciptor\n", me)); + ("\tProcessRequest(0x%p): receiving desciptor\n", me)); bytes = PR_Recv( fd, descriptor, sizeof(*descriptor), RECV_FLAGS, timeout); if (-1 == bytes) @@ -423,7 +409,7 @@ static PRStatus ProcessRequest(PRFileDesc *fd, CSServer_t *server) { TEST_LOG( cltsrv_log_file, TEST_LOG_ERROR, - ("\tProcessRequest(0x%lx): receive timeout\n", me)); + ("\tProcessRequest(0x%p): receive timeout\n", me)); } goto exit; } @@ -432,7 +418,7 @@ static PRStatus ProcessRequest(PRFileDesc *fd, CSServer_t *server) rv = PR_FAILURE; TEST_LOG( cltsrv_log_file, TEST_LOG_ERROR, - ("\tProcessRequest(0x%lx): unexpected end of file\n", me)); + ("\tProcessRequest(0x%p): unexpected end of file\n", me)); goto exit; } descbytes = PR_ntohl(descriptor->size); @@ -440,7 +426,7 @@ static PRStatus ProcessRequest(PRFileDesc *fd, CSServer_t *server) TEST_LOG( cltsrv_log_file, TEST_LOG_VERBOSE, - ("\t\tProcessRequest(0x%lx): read descriptor {%ld, %s}\n", + ("\t\tProcessRequest(0x%p): read descriptor {%d, %s}\n", me, descbytes, descriptor->filename)); file = PR_Open( @@ -453,7 +439,7 @@ static PRStatus ProcessRequest(PRFileDesc *fd, CSServer_t *server) { TEST_LOG( cltsrv_log_file, TEST_LOG_ERROR, - ("\tProcessRequest(0x%lx): open file timeout\n", me)); + ("\tProcessRequest(0x%p): open file timeout\n", me)); goto aborted; } } @@ -467,7 +453,7 @@ static PRStatus ProcessRequest(PRFileDesc *fd, CSServer_t *server) netbytes = descbytes - filebytes; TEST_LOG( cltsrv_log_file, TEST_LOG_VERBOSE, - ("\tProcessRequest(0x%lx): receive %d bytes\n", me, netbytes)); + ("\tProcessRequest(0x%p): receive %d bytes\n", me, netbytes)); bytes = PR_Recv(fd, buffer, netbytes, RECV_FLAGS, timeout); if (-1 == bytes) { @@ -477,7 +463,7 @@ static PRStatus ProcessRequest(PRFileDesc *fd, CSServer_t *server) { TEST_LOG( cltsrv_log_file, TEST_LOG_ERROR, - ("\t\tProcessRequest(0x%lx): receive data timeout\n", me)); + ("\t\tProcessRequest(0x%p): receive data timeout\n", me)); goto aborted; } /* @@ -487,7 +473,7 @@ static PRStatus ProcessRequest(PRFileDesc *fd, CSServer_t *server) */ TEST_LOG( cltsrv_log_file, TEST_LOG_WARNING, - ("\t\tProcessRequest(0x%lx): unexpected error (%d, %d)\n", + ("\t\tProcessRequest(0x%p): unexpected error (%d, %d)\n", me, PR_GetError(), PR_GetOSError())); goto aborted; } @@ -495,7 +481,7 @@ static PRStatus ProcessRequest(PRFileDesc *fd, CSServer_t *server) { TEST_LOG( cltsrv_log_file, TEST_LOG_WARNING, - ("\t\tProcessRequest(0x%lx): unexpected end of stream\n", me)); + ("\t\tProcessRequest(0x%p): unexpected end of stream\n", me)); rv = PR_FAILURE; goto aborted; } @@ -505,7 +491,7 @@ static PRStatus ProcessRequest(PRFileDesc *fd, CSServer_t *server) MY_ASSERT(netbytes > 0); TEST_LOG( cltsrv_log_file, TEST_LOG_VERBOSE, - ("\tProcessRequest(0x%lx): write %d bytes to file\n", me, netbytes)); + ("\tProcessRequest(0x%p): write %d bytes to file\n", me, netbytes)); bytes = PR_Write(file, buffer, netbytes); if (netbytes != bytes) { @@ -515,7 +501,7 @@ static PRStatus ProcessRequest(PRFileDesc *fd, CSServer_t *server) { TEST_LOG( cltsrv_log_file, TEST_LOG_ERROR, - ("\t\tProcessRequest(0x%lx): write file timeout\n", me)); + ("\t\tProcessRequest(0x%p): write file timeout\n", me)); goto aborted; } } @@ -533,7 +519,7 @@ static PRStatus ProcessRequest(PRFileDesc *fd, CSServer_t *server) TEST_LOG( cltsrv_log_file, TEST_LOG_VERBOSE, - ("\t\tProcessRequest(0x%lx): opening %s\n", me, descriptor->filename)); + ("\t\tProcessRequest(0x%p): opening %s\n", me, descriptor->filename)); file = PR_Open(descriptor->filename, PR_RDONLY, 0); if (NULL == file) { @@ -543,13 +529,13 @@ static PRStatus ProcessRequest(PRFileDesc *fd, CSServer_t *server) { TEST_LOG( cltsrv_log_file, TEST_LOG_ERROR, - ("\t\tProcessRequest(0x%lx): open file timeout\n", + ("\t\tProcessRequest(0x%p): open file timeout\n", PR_CurrentThread())); goto aborted; } TEST_LOG( cltsrv_log_file, TEST_LOG_ERROR, - ("\t\tProcessRequest(0x%lx): other file open error (%u, %u)\n", + ("\t\tProcessRequest(0x%p): other file open error (%u, %u)\n", me, PR_GetError(), PR_GetOSError())); goto aborted; } @@ -563,7 +549,7 @@ static PRStatus ProcessRequest(PRFileDesc *fd, CSServer_t *server) filebytes = descbytes - netbytes; TEST_LOG( cltsrv_log_file, TEST_LOG_VERBOSE, - ("\tProcessRequest(0x%lx): read %d bytes from file\n", me, filebytes)); + ("\tProcessRequest(0x%p): read %d bytes from file\n", me, filebytes)); bytes = PR_Read(file, buffer, filebytes); if (filebytes != bytes) { @@ -572,11 +558,11 @@ static PRStatus ProcessRequest(PRFileDesc *fd, CSServer_t *server) if (PR_IO_TIMEOUT_ERROR == PR_GetError()) TEST_LOG( cltsrv_log_file, TEST_LOG_ERROR, - ("\t\tProcessRequest(0x%lx): read file timeout\n", me)); + ("\t\tProcessRequest(0x%p): read file timeout\n", me)); else TEST_LOG( cltsrv_log_file, TEST_LOG_ERROR, - ("\t\tProcessRequest(0x%lx): other file error (%d, %d)\n", + ("\t\tProcessRequest(0x%p): other file error (%d, %d)\n", me, PR_GetError(), PR_GetOSError())); goto aborted; } @@ -585,7 +571,7 @@ static PRStatus ProcessRequest(PRFileDesc *fd, CSServer_t *server) filebytes = bytes; TEST_LOG( cltsrv_log_file, TEST_LOG_VERBOSE, - ("\t\tProcessRequest(0x%lx): sending %d bytes\n", me, filebytes)); + ("\t\tProcessRequest(0x%p): sending %d bytes\n", me, filebytes)); bytes = PR_Send(fd, buffer, filebytes, SEND_FLAGS, timeout); if (filebytes != bytes) { @@ -595,7 +581,7 @@ static PRStatus ProcessRequest(PRFileDesc *fd, CSServer_t *server) { TEST_LOG( cltsrv_log_file, TEST_LOG_ERROR, - ("\t\tProcessRequest(0x%lx): send data timeout\n", me)); + ("\t\tProcessRequest(0x%p): send data timeout\n", me)); goto aborted; } break; @@ -622,7 +608,7 @@ aborted: exit: TEST_LOG( cltsrv_log_file, TEST_LOG_VERBOSE, - ("\t\tProcessRequest(0x%lx): Finished\n", me)); + ("\t\tProcessRequest(0x%p): Finished\n", me)); PR_DELETE(descriptor); @@ -648,7 +634,7 @@ static PRStatus CreateWorker(CSServer_t *server, CSPool_t *pool) } TEST_LOG(cltsrv_log_file, TEST_LOG_STATUS, - ("\tCreateWorker(0x%lx): create new worker (0x%lx)\n", + ("\tCreateWorker(0x%p): create new worker (0x%p)\n", PR_CurrentThread(), worker->thread)); return PR_SUCCESS; @@ -666,7 +652,7 @@ static void PR_CALLBACK Worker(void *arg) TEST_LOG( cltsrv_log_file, TEST_LOG_NOTICE, - ("\t\tWorker(0x%lx): started [%lu]\n", me, pool->workers + 1)); + ("\t\tWorker(0x%p): started [%u]\n", me, pool->workers + 1)); PR_Lock(server->ml); PR_APPEND_LINK(&worker->element, &server->list); @@ -678,14 +664,14 @@ static void PR_CALLBACK Worker(void *arg) { TEST_LOG( cltsrv_log_file, TEST_LOG_VERBOSE, - ("\t\tWorker(0x%lx): waiting for accept slot[%d]\n", + ("\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%lx): has been %s\n", + ("\tWorker(0x%p): has been %s\n", me, (Aborted(rv) ? "interrupted" : "stopped"))); goto exit; } @@ -695,7 +681,7 @@ static void PR_CALLBACK Worker(void *arg) TEST_LOG( cltsrv_log_file, TEST_LOG_VERBOSE, - ("\t\tWorker(0x%lx): calling accept\n", me)); + ("\t\tWorker(0x%p): calling accept\n", me)); fd = PR_Accept(server->listener, &from, PR_INTERVAL_NO_TIMEOUT); PR_Lock(server->ml); @@ -736,7 +722,7 @@ static void PR_CALLBACK Worker(void *arg) if (PR_SUCCESS != rv) TEST_LOG( cltsrv_log_file, TEST_LOG_ERROR, - ("\t\tWorker(0x%lx): server process ended abnormally\n", me)); + ("\t\tWorker(0x%p): server process ended abnormally\n", me)); (void)PR_Close(fd); fd = NULL; PR_Lock(server->ml); @@ -756,7 +742,7 @@ exit: TEST_LOG( cltsrv_log_file, TEST_LOG_NOTICE, - ("\t\tWorker(0x%lx): exiting [%lu]\n", PR_CurrentThread(), pool->workers)); + ("\t\tWorker(0x%p): exiting [%u]\n", PR_CurrentThread(), pool->workers)); PR_Lock(server->ml); pool->workers -= 1; /* undefine our existance */ @@ -809,7 +795,7 @@ static void PR_CALLBACK Server(void *arg) */ TEST_LOG( cltsrv_log_file, TEST_LOG_VERBOSE, - ("\tServer(0x%lx): waiting for state change\n", me)); + ("\tServer(0x%p): waiting for state change\n", me)); PR_Lock(server->ml); while ((cs_run == server->state) && !Aborted(rv)) @@ -821,7 +807,7 @@ static void PR_CALLBACK Server(void *arg) TEST_LOG( cltsrv_log_file, TEST_LOG_INFO, - ("\tServer(0x%lx): shutting down workers\n", me)); + ("\tServer(0x%p): shutting down workers\n", me)); /* ** Get all the worker threads to exit. They know how to @@ -838,7 +824,7 @@ static void PR_CALLBACK Server(void *arg) CSWorker_t *worker = (CSWorker_t*)head; TEST_LOG( cltsrv_log_file, TEST_LOG_VERBOSE, - ("\tServer(0x%lx): interrupting worker(0x%lx)\n", me, worker)); + ("\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); @@ -848,7 +834,7 @@ static void PR_CALLBACK Server(void *arg) { TEST_LOG( cltsrv_log_file, TEST_LOG_NOTICE, - ("\tServer(0x%lx): waiting for %lu workers to exit\n", + ("\tServer(0x%p): waiting for %u workers to exit\n", me, server->pool.workers)); (void)PR_WaitCondVar(server->pool.exiting, PR_INTERVAL_NO_TIMEOUT); } @@ -859,7 +845,7 @@ static void PR_CALLBACK Server(void *arg) TEST_LOG( cltsrv_log_file, TEST_LOG_ALWAYS, - ("\tServer(0x%lx): stopped after %lu operations and %lu bytes\n", + ("\tServer(0x%p): stopped after %u operations and %u bytes\n", me, server->operations, server->bytesTransferred)); if (NULL != server->listener) PR_Close(server->listener); @@ -867,26 +853,15 @@ static void PR_CALLBACK Server(void *arg) } /* Server */ -#if defined(DEBUG) && defined(_PR_PTHREADS) -static void PrintPthreadStats(void) -{ - PT_FPrintStats(debug_out, "\nPThread Statistics\n"); -} /* PrintPthreadStats */ -#endif /* defined(DEBUG) && defined(_PR_PTHREADS) */ - static void WaitForCompletion(PRIntn execution) { -#if defined(DEBUG) && defined(_PR_PTHREADS) while (execution > 0) { PRIntn dally = (execution > 30) ? 30 : execution; PR_Sleep(PR_SecondsToInterval(dally)); - if (pthread_stats) PrintPthreadStats(); + if (pthread_stats) PT_FPrintStats(debug_out, "\nPThread Statistics\n"); execution -= dally; } -#else - PR_Sleep(PR_SecondsToInterval(execution)); -#endif /* defined(DEBUG) && defined(_PR_PTHREADS) */ } /* WaitForCompletion */ static void Help(void) @@ -895,6 +870,8 @@ static void Help(void) 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"); @@ -932,12 +909,15 @@ PRIntn main(PRIntn argc, char** argv) 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 @@ -946,7 +926,7 @@ PRIntn main(PRIntn argc, char** argv) */ PLOptStatus os; - PLOptState *opt = PL_CreateOptState(argc, argv, "GX6b:a:c:w:W:e:s:vdhp"); + PLOptState *opt = PL_CreateOptState(argc, argv, "GX6b:a:c:f:F:w:W:e:s:vdhp"); debug_out = PR_GetSpecialFD(PR_StandardError); @@ -976,6 +956,12 @@ PRIntn main(PRIntn argc, char** argv) 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; @@ -1026,12 +1012,15 @@ PRIntn main(PRIntn argc, char** argv) debug_mode = PR_TRUE; #endif + 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%lx): starting server\n", PR_CurrentThread())); + ("main(0x%p): starting server\n", PR_CurrentThread())); server = PR_NEWZAP(CSServer_t); PR_INIT_CLIST(&server->list); @@ -1048,7 +1037,7 @@ PRIntn main(PRIntn argc, char** argv) TEST_LOG( cltsrv_log_file, TEST_LOG_NOTICE, - ("main(0x%lx): creating server thread\n", PR_CurrentThread())); + ("main(0x%p): creating server thread\n", PR_CurrentThread())); server->thread = PR_CreateThread( PR_USER_THREAD, Server, server, PR_PRIORITY_HIGH, @@ -1057,7 +1046,7 @@ PRIntn main(PRIntn argc, char** argv) TEST_LOG( cltsrv_log_file, TEST_LOG_VERBOSE, - ("main(0x%lx): waiting for server init\n", PR_CurrentThread())); + ("main(0x%p): waiting for server init\n", PR_CurrentThread())); PR_Lock(server->ml); while (server->state == cs_init) @@ -1066,7 +1055,7 @@ PRIntn main(PRIntn argc, char** argv) TEST_LOG( cltsrv_log_file, TEST_LOG_VERBOSE, - ("main(0x%lx): server init complete (port #%d)\n", + ("main(0x%p): server init complete (port #%d)\n", PR_CurrentThread(), server->port)); } @@ -1079,7 +1068,7 @@ PRIntn main(PRIntn argc, char** argv) TEST_LOG( cltsrv_log_file, TEST_LOG_VERBOSE, - ("main(0x%lx): creating %d client threads\n", + ("main(0x%p): creating %d client threads\n", PR_CurrentThread(), clients)); if (!serverIsLocal) @@ -1110,7 +1099,7 @@ PRIntn main(PRIntn argc, char** argv) client[index].stateChange = PR_NewCondVar(client[index].ml); TEST_LOG( cltsrv_log_file, TEST_LOG_INFO, - ("main(0x%lx): creating client threads\n", PR_CurrentThread())); + ("main(0x%p): creating client threads\n", PR_CurrentThread())); client[index].thread = PR_CreateThread( PR_USER_THREAD, Client, &client[index], PR_PRIORITY_NORMAL, thread_scope, PR_JOINABLE_THREAD, 0); @@ -1125,7 +1114,7 @@ PRIntn main(PRIntn argc, char** argv) /* Then just let them go at it for a bit */ TEST_LOG( cltsrv_log_file, TEST_LOG_ALWAYS, - ("main(0x%lx): waiting for execution interval (%d seconds)\n", + ("main(0x%p): waiting for execution interval (%d seconds)\n", PR_CurrentThread(), execution)); WaitForCompletion(execution); @@ -1137,7 +1126,7 @@ PRIntn main(PRIntn argc, char** argv) for (index = 0; index < clients; ++index) { TEST_LOG(cltsrv_log_file, TEST_LOG_STATUS, - ("main(0x%lx): notifying client(0x%lx) to stop\n", + ("main(0x%p): notifying client(0x%p) to stop\n", PR_CurrentThread(), client[index].thread)); PR_Lock(client[index].ml); @@ -1152,7 +1141,7 @@ PRIntn main(PRIntn argc, char** argv) PR_Unlock(client[index].ml); TEST_LOG(cltsrv_log_file, TEST_LOG_VERBOSE, - ("main(0x%lx): joining client(0x%lx)\n", + ("main(0x%p): joining client(0x%p)\n", PR_CurrentThread(), client[index].thread)); joinStatus = PR_JoinThread(client[index].thread); @@ -1168,7 +1157,7 @@ PRIntn main(PRIntn argc, char** argv) /* All clients joined - retrieve the server */ TEST_LOG( cltsrv_log_file, TEST_LOG_NOTICE, - ("main(0x%lx): notifying server(0x%lx) to stop\n", + ("main(0x%p): notifying server(0x%p) to stop\n", PR_CurrentThread(), server->thread)); PR_Lock(server->ml); @@ -1180,7 +1169,7 @@ PRIntn main(PRIntn argc, char** argv) TEST_LOG( cltsrv_log_file, TEST_LOG_NOTICE, - ("main(0x%lx): joining server(0x%lx)\n", + ("main(0x%p): joining server(0x%p)\n", PR_CurrentThread(), server->thread)); joinStatus = PR_JoinThread(server->thread); TEST_ASSERT(PR_SUCCESS == joinStatus); @@ -1194,13 +1183,12 @@ PRIntn main(PRIntn argc, char** argv) TEST_LOG( cltsrv_log_file, TEST_LOG_ALWAYS, - ("main(0x%lx): test complete\n", PR_CurrentThread())); + ("main(0x%p): test complete\n", PR_CurrentThread())); -#if defined(DEBUG) && defined(_PR_PTHREADS) - PrintPthreadStats(); -#endif /* defined(DEBUG) && defined(_PR_PTHREADS) */ + PT_FPrintStats(debug_out, "\nPThread Statistics\n"); TimeOfDayMessage("Test exiting at", PR_CurrentThread()); + PR_Cleanup(); return 0; } /* main */ diff --git a/pr/tests/concur.c b/pr/tests/concur.c index 88575dd5..fa2bfa1f 100644 --- a/pr/tests/concur.c +++ b/pr/tests/concur.c @@ -26,6 +26,8 @@ #include "prinrval.h" #include "prlock.h" #include "prprf.h" +#include "prmem.h" +#include "prlog.h" #include "plgetopt.h" @@ -37,7 +39,7 @@ #include <stdlib.h> -#define DEFAULT_RANGE 20 +#define DEFAULT_RANGE 10 #define DEFAULT_LOOPS 100 static PRThreadScope thread_scope = PR_LOCAL_THREAD; @@ -71,8 +73,11 @@ 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:"); @@ -109,16 +114,17 @@ PRIntn PR_CALLBACK Concur(PRIntn argc, char **argv) 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) + for (cpus = 1; cpus <= range; ++cpus) { PR_SetConcurrency(cpus); context.want = cpus; - (void)PR_CreateThread( + threads[cpus - 1] = PR_CreateThread( PR_USER_THREAD, Dull, &context, PR_PRIORITY_NORMAL, - thread_scope, PR_UNJOINABLE_THREAD, 0); + thread_scope, PR_JOINABLE_THREAD, 0); } PR_Sleep(hundredMills); @@ -132,6 +138,10 @@ PRIntn PR_CALLBACK Concur(PRIntn argc, char **argv) PR_NotifyCondVar(context.cv); PR_Unlock(context.ml); } + for(cnt = 0; cnt < range; cnt++) { + rc = PR_JoinThread(threads[cnt]); + PR_ASSERT(rc == PR_SUCCESS); + } } diff --git a/pr/tests/cvar2.c b/pr/tests/cvar2.c index f6b34268..f2508a7b 100644 --- a/pr/tests/cvar2.c +++ b/pr/tests/cvar2.c @@ -35,6 +35,7 @@ ***********************************************************************/ #include "nspr.h" +#include "plerror.h" #include "plgetopt.h" #include <stdio.h> @@ -167,8 +168,8 @@ CreateTestThread(threadinfo *info, scope, PR_JOINABLE_THREAD, 0); - if (!info->thread) - printf("error creating thread\n"); + if (!info->thread) + PL_PrintError("error creating thread\n"); } diff --git a/pr/tests/dceemu.c b/pr/tests/dceemu.c index 7935eae8..cb04cbd6 100644 --- a/pr/tests/dceemu.c +++ b/pr/tests/dceemu.c @@ -36,7 +36,7 @@ ***********************************************************************/ -#if defined(XP_UNIX) +#if defined(_PR_DCETHREADS) #include "prlog.h" #include "prinit.h" @@ -93,12 +93,12 @@ static PRIntn prmain(PRIntn argc, char **argv) } /* prmain */ -#endif /* #if defined(XP_UNIX) */ +#endif /* #if defined(_PR_DCETHREADS) */ int main(int argc, char **argv) { -#if defined(XP_UNIX) +#if defined(_PR_DCETHREADS) PR_Initialize(prmain, argc, argv, 0); if(failed_already) return 1; diff --git a/pr/tests/dll/Makefile b/pr/tests/dll/Makefile index 7afc7300..c2f72d71 100644 --- a/pr/tests/dll/Makefile +++ b/pr/tests/dll/Makefile @@ -58,7 +58,9 @@ else TARGETS = $(SHARED_LIBRARY) $(IMPORT_LIBRARY) endif else +ifdef MKSHLIB SHARED_LIBRARY = $(OBJDIR)/libmy.$(DLL_SUFFIX) +endif TARGETS = $(SHARED_LIBRARY) endif @@ -81,6 +83,7 @@ OS_DLL_OPTION = NOCASEEXACT OS_LIB_FLAGS = -irn endif +ifdef SHARED_LIBRARY export:: $(TARGETS) $(NSINSTALL) $(TARGETS) ../$(OBJDIR)/dll @@ -88,3 +91,4 @@ install:: export clean:: rm -rf $(TARGETS) +endif diff --git a/pr/tests/dlltest.c b/pr/tests/dlltest.c index bd8f7c49..bc817a05 100644 --- a/pr/tests/dlltest.c +++ b/pr/tests/dlltest.c @@ -84,15 +84,15 @@ int main(int argc, char** argv) fprintf( stderr, "PR_LoadLibrary failed (%d, %d, %s)\n", PR_GetError(), PR_GetOSError(), text); - if (!debug_mode) failed_already=1; + if (!debug_mode) failed_already=1; } getFcn = (GetFcnType) PR_FindSymbol(lib, "My_GetValue"); setFcn = (SetFcnType) PR_FindSymbol(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; + 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"); @@ -103,26 +103,24 @@ int main(int argc, char** argv) */ getFcn = (GetFcnType) PR_FindSymbolAndLibrary("My_GetValue", &lib2); - if (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; - + 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; - + 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; + 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"); @@ -133,19 +131,19 @@ int main(int argc, char** argv) 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; + 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_FindSymbol(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; + 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"); @@ -155,21 +153,21 @@ int main(int argc, char** argv) 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; + fprintf(stderr, "Test 4 failed: cannot unload library: (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + if (!debug_mode) failed_already=1; + goto exit_now; } - status = PR_UnloadLibrary(lib2); - if (PR_FAILURE != status || PR_GetError() != PR_INVALID_ARGUMENT_ERROR) { - fprintf(stderr, "Test 4 failed: how can an already unloaded library " - "be unloaded again?\n"); - if (!debug_mode) failed_already=1; - goto exit_now; + getFcn = (GetFcnType) PR_FindSymbolAndLibrary("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"); - } + printf("Test 4 passed\n"); + } /* ** Test 5: LoadStaticLibrary() @@ -181,21 +179,24 @@ int main(int argc, char** argv) lib = PR_LoadStaticLibrary( "my.dll", slt ); if ( lib == NULL ) { - printf("dlltest: Test 5: LoadStatiLibrary() failed\n" ); + fprintf(stderr, "Test 5: LoadStatiLibrary() failed\n" ); goto exit_now; } - printf("Test 5 passed\n"); + if (debug_mode) + { + printf("Test 5 passed\n"); + } } - goto exit_now; + goto exit_now; exit_now: PR_Cleanup(); if (failed_already) { printf("FAILED\n"); - return 1; + return 1; } else { printf("PASSED\n"); - return 0; + return 0; } } diff --git a/pr/tests/foreign.c b/pr/tests/foreign.c new file mode 100644 index 00000000..dcf88250 --- /dev/null +++ b/pr/tests/foreign.c @@ -0,0 +1,345 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +/* +** File: 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) && !defined(_PR_DCETHREADS) +#include "md/_pth.h" +#include <pthread.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) && !defined(_PR_DCETHREADS) */ + +#if defined(IRIX) && !defined(_PR_PTHREADS) +#include <sys/types.h> +#include <sys/prctl.h> +static void sproc_start(void *arg, PRSize size) +{ + StartObject *so = (StartObject*)arg; + StartFn start = so->start; + void *data = so->arg; + PR_Free(so); + start(data); +} /* sproc_start */ +#endif /* defined(IRIX) && !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 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) && !defined(_PR_DCETHREADS) + { + 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 = PTHREAD_ATTR_INIT(&tattr); + PR_ASSERT(0 == rv); + + rv = pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED); + PR_ASSERT(0 == rv); + +#if !defined(LINUX) + rv = pthread_attr_setstacksize(&tattr, 64 * 1024); + PR_ASSERT(0 == rv); +#endif + + rv = PTHREAD_CREATE(&id, tattr, pthread_start, start_object); + (void)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) && !defined(_PR_DCETHREADS) */ + + case thread_sproc: +#if defined(IRIX) && !defined(_PR_PTHREADS) + { + PRInt32 pid; + StartObject *start_object; + start_object = PR_NEW(StartObject); + PR_ASSERT(NULL != start_object); + start_object->start = start; + start_object->arg = arg; + pid = sprocsp( + sproc_start, PR_SALL, start_object, NULL, 64 * 1024); + rv = (0 < pid) ? PR_SUCCESS : PR_FAILURE; + } +#else + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + rv = PR_FAILURE; +#endif /* defined(IRIX) && !defined(_PR_PTHREADS) */ + 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 */ + 0U, /*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; +} /* CreateThread */ + +static void PR_CALLBACK lazyEntry(void *arg) +{ + PR_ASSERT(NULL == arg); +} /* lazyEntry */ + + +static void OneShot(void *arg) +{ + PRUintn pdkey; + PRFileDesc *pair[2]; + PRIntn test = (PRIntn)arg; + + for (test = 0; test < 11; ++test) { + + switch (test) + { + case 0: + (void)PR_NewLock(); + DPRINTF((output,"Thread[0x%x] called PR_NewLock\n", + PR_GetCurrentThread())); + 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: + (void)PR_Open("/usr/tmp/", PR_RDONLY, 0); + DPRINTF((output,"Thread[0x%x] called PR_Open\n", + PR_GetCurrentThread())); + break; + + case 4: + (void)PR_NewUDPSocket(); + DPRINTF((output,"Thread[0x%x] called PR_NewUDPSocket\n", + PR_GetCurrentThread())); + break; + + case 5: + (void)PR_NewTCPSocket(); + DPRINTF((output,"Thread[0x%x] called PR_NewTCPSocket\n", + PR_GetCurrentThread())); + break; + + case 6: + (void)PR_OpenDir("/usr/tmp/"); + DPRINTF((output,"Thread[0x%x] called PR_OpenDir\n", + PR_GetCurrentThread())); + 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())); + break; + + case 10: + PR_SetConcurrency(2); + DPRINTF((output,"Thread[0x%x] called PR_SetConcurrency\n", + PR_GetCurrentThread())); + break; + + default: + break; + } /* switch() */ + } +} /* OneShot */ + +PRIntn main(PRIntn argc, char **argv) +{ + PRStatus rv; + PRIntn test_number; + 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; +#elif defined(IRIX) + thread_provider = thread_sproc; +#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 = 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/pr/tests/forktest.c b/pr/tests/forktest.c index b52499d5..ecb09c5b 100644 --- a/pr/tests/forktest.c +++ b/pr/tests/forktest.c @@ -40,6 +40,7 @@ #include "plgetopt.h" #include "nspr.h" +#include <string.h> #include <stdio.h> #include <stdlib.h> @@ -259,6 +260,7 @@ char *argv[] ) { pid_t pid; + int rv; /* main test program */ @@ -275,9 +277,18 @@ char *argv[] printf("Fork succeeded. Parent process continues.\n"); DoIO(); - if (waitpid(pid, &childStatus, 0) != pid) { - fprintf(stderr, "waitpid failed: %d\n", errno); - failed_already = 1; + if ((rv = waitpid(pid, &childStatus, 0)) != pid) { +#if defined(IRIX) && !defined(_PR_PTHREADS) + /* + * nspr may handle SIGCLD signal + */ + if ((rv < 0) && (errno == ECHILD)) { + } else +#endif + { + fprintf(stderr, "waitpid failed: %d\n", errno); + failed_already = 1; + } } else if (!WIFEXITED(childStatus) || WEXITSTATUS(childStatus) != 0) { failed_already = 1; @@ -290,6 +301,10 @@ char *argv[] } return failed_already; } else { +#if defined(IRIX) && !defined(_PR_PTHREADS) + extern void _PR_IRIX_CHILD_PROCESS(void); + _PR_IRIX_CHILD_PROCESS(); +#endif printf("Fork succeeded. Child process continues.\n"); DoIO(); printf("Child process exits.\n"); diff --git a/pr/tests/initclk.c b/pr/tests/initclk.c new file mode 100644 index 00000000..a815997f --- /dev/null +++ b/pr/tests/initclk.c @@ -0,0 +1,87 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +/* + * 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> + +/* 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() +{ + 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("PASS\n"); + return 0; +} diff --git a/pr/tests/inrval.c b/pr/tests/inrval.c index b963da48..ce1df9cc 100644 --- a/pr/tests/inrval.c +++ b/pr/tests/inrval.c @@ -40,6 +40,9 @@ #else #include "obsolete/pralarm.h" #endif + +#include "prio.h" +#include "prprf.h" #include "prlock.h" #include "prlong.h" #include "prcvar.h" @@ -51,14 +54,8 @@ #include <stdio.h> #include <stdlib.h> -#ifdef XP_MAC -#include "prlog.h" -#define printf PR_LogPrint -extern void SetupMacPrintfLog(char *logFile); -#endif - -PRIntn failed_already=0; -PRIntn debug_mode; +static PRIntn debug_mode; +static PRFileDesc *output; static void TestConversions(void) @@ -66,26 +63,62 @@ static void TestConversions(void) PRIntervalTime ticks = PR_TicksPerSecond(); if (debug_mode) { - printf("PR_TicksPerSecond: %ld\n\n", ticks); - printf("PR_SecondsToInterval(1): %ld\n", PR_SecondsToInterval(1)); - printf("PR_MillisecondsToInterval(1000): %ld\n", PR_MillisecondsToInterval(1000)); - printf("PR_MicrosecondsToInterval(1000000): %ld\n\n", PR_MicrosecondsToInterval(1000000)); + 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)); - printf("PR_SecondsToInterval(3): %ld\n", PR_SecondsToInterval(3)); - printf("PR_MillisecondsToInterval(3000): %ld\n", PR_MillisecondsToInterval(3000)); - printf("PR_MicrosecondsToInterval(3000000): %ld\n\n", PR_MicrosecondsToInterval(3000000)); + 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)); - printf("PR_IntervalToSeconds(%ld): %ld\n", ticks, PR_IntervalToSeconds(ticks)); - printf("PR_IntervalToMilliseconds(%ld): %ld\n", ticks, PR_IntervalToMilliseconds(ticks)); - printf("PR_IntervalToMicroseconds(%ld): %ld\n\n", ticks, PR_IntervalToMicroseconds(ticks)); + 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; - printf("PR_IntervalToSeconds(%ld): %ld\n", ticks, PR_IntervalToSeconds(ticks)); - printf("PR_IntervalToMilliseconds(%ld): %ld\n", ticks, PR_IntervalToMilliseconds(ticks)); - printf("PR_IntervalToMicroseconds(%ld): %ld\n\n", ticks, PR_IntervalToMicroseconds(ticks)); + 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; @@ -107,58 +140,18 @@ static void TestIntervals(void) LL_I2L(thousand, 1000); LL_DIV(elapsed, elapsed, thousand); LL_L2UI(delta, elapsed); - if (debug_mode) printf( + 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) printf("\n"); + if (debug_mode) PR_fprintf(output, "\n"); } /* TestIntervals */ -static PRUint32 GetInterval(PRUint32 loops) -{ - PRIntervalTime interval = 0; - while (loops-- > 0) interval += PR_IntervalNow(); - return 0; -} /* GetInterval */ - -static PRUint32 TimeThis( - const char *msg, PRUint32 (*func)(PRUint32 loops), PRUint32 loops) -{ - PRUint32 overhead, usecs32; - PRTime timein, timeout, usecs; - - timein = PR_Now(); - overhead = func(loops); - timeout = PR_Now(); - - LL_SUB(usecs, timeout, timein); - LL_L2I(usecs32, usecs); - - if(usecs32 < overhead) - { - if (debug_mode) { - printf("%s ran in negative time\n", msg); - printf(" predicted overhead was %ld usecs\n", overhead); - printf(" test completed in %ld usecs\n\n", usecs); - } - } - else - { - if (debug_mode) - printf( - "%s [\n\ttotal: %ld usecs\n\toverhead: %ld usecs\n\tcost: %6.3f usecs]\n\n", - msg, usecs, overhead, - ((double)(usecs32 - overhead) / (double)loops)); - } - - return overhead; -} /* TimeThis */ - static PRIntn PR_CALLBACK RealMain(int argc, char** argv) { - PRUint32 cpu, cpus = 2, loops = 1000; + 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. @@ -191,42 +184,28 @@ static PRIntn PR_CALLBACK RealMain(int argc, char** argv) } PL_DestroyOptState(opt); + output = PR_GetSpecialFD(PR_StandardOutput); + PR_fprintf(output, "inrval: Examine stdout to determine results.\n"); - printf("inrval: Examine stdout to determine results.\n"); - - if (cpus == 0) cpus = 2; + if (cpus == 0) cpus = 8; if (loops == 0) loops = 1000; - if (debug_mode) printf("Inrval: Using %d loops\n", loops); - - - cpus = (argc < 3) ? 2 : atoi(argv[2]); - if (cpus == 0) cpus = 2; - if (debug_mode) printf("Inrval: Using %d cpu(s)\n", cpus); if (debug_mode > 0) { - printf("Inrval: Using %d loops\n", loops); - printf("Inrval: Using %d cpu(s)\n", cpus); + PR_fprintf(output, "Inrval: Using %d loops\n", loops); + PR_fprintf(output, "Inrval: Using 1 and %d cpu(s)\n", cpus); } -#ifdef XP_MAC - SetupMacPrintfLog("inrval.log"); - debug_mode = 1; -#endif - - for (cpu = 1; cpu <= cpus; ++cpu) + 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); - if (debug_mode) printf("\nInrval: Using %d CPU(s)\n", cpu); - if (debug_mode > 0) - printf("\nInrval: Using %d CPU(s)\n", cpu); - - PR_SetConcurrency(cpu); - + TestNowOverhead(); + TestIntervalOverhead(); TestConversions(); TestIntervals(); - - (void)TimeThis("GetInterval", GetInterval, loops); } return 0; diff --git a/pr/tests/instrumt.c b/pr/tests/instrumt.c new file mode 100644 index 00000000..5a51a9f3 --- /dev/null +++ b/pr/tests/instrumt.c @@ -0,0 +1,470 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +/* +** File: 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 ); + char *qn, *rn, *dn; + 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 ); + tCtr = 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 ); + char *qn, *rn, *dn; + 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; + PR_DEFINE_COUNTER( tc ); + + PR_LOG( lm, msgLevel, + ("Begin CounterTest")); + + 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_ASSERT( i == size ); + + 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() */ + + +PRIntn main(PRIntn 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_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/pr/tests/ipv6.c b/pr/tests/ipv6.c index 63ddfbf6..15303430 100644 --- a/pr/tests/ipv6.c +++ b/pr/tests/ipv6.c @@ -17,10 +17,13 @@ */ #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" @@ -37,8 +40,9 @@ static PRFileDesc *err = NULL; static void Help(void) { - PR_fprintf(err, "Usage: [-t s] [-s] [-h]\n"); + PR_fprintf(err, "Usage: [-V] [-6] [-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-6 First turn on IPv6 capability (default: FALSE)\n"); PR_fprintf(err, "\t-h This message and nothing else\n"); } /* Help */ @@ -91,8 +95,8 @@ PRIntn main(PRIntn argc, char **argv) PRProtoEnt proto; PRBool ipv6 = PR_FALSE; const char *name = NULL; - PRBool failed = PR_FALSE; - PLOptState *opt = PL_CreateOptState(argc, argv, "h6"); + PRBool failed = PR_FALSE, version = PR_FALSE; + PLOptState *opt = PL_CreateOptState(argc, argv, "Vh6"); err = PR_GetSpecialFD(PR_StandardError); @@ -107,6 +111,9 @@ PRIntn main(PRIntn argc, char **argv) case '6': /* Turn on IPv6 mode */ ipv6 = PR_TRUE; break; + case 'V': /* Do version discovery */ + version = PR_TRUE; + break; case 'h': /* user wants some guidance */ default: Help(); /* so give him an earful */ @@ -115,6 +122,58 @@ PRIntn main(PRIntn argc, char **argv) } PL_DestroyOptState(opt); + if (version) + { +#if defined(XP_UNIX) +#define NSPR_LIB "nspr21" +#elif defined(WIN32) +#define NSPR_LIB "libnspr21" +#else +#error "Architecture not supported" +#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 (ipv6) { rv = PR_SetIPv6Enable(ipv6); diff --git a/pr/tests/joinkk.c b/pr/tests/joinkk.c index f3b5396d..5c2e4e9c 100644 --- a/pr/tests/joinkk.c +++ b/pr/tests/joinkk.c @@ -154,12 +154,12 @@ static PRIntn PR_CALLBACK RealMain( PRIntn argc, char **argv ) if(failed_already) { printf("FAIL\n"); - return 0; + return 1; } else { printf("PASS\n"); - return 1; + return 0; } } diff --git a/pr/tests/layer.c b/pr/tests/layer.c index e6be944f..0c93e4b6 100644 --- a/pr/tests/layer.c +++ b/pr/tests/layer.c @@ -64,6 +64,7 @@ static PRFileDesc *PushLayer(PRFileDesc *stack) return stack; } /* PushLayer */ +#if 0 static PRFileDesc *PopLayer(PRFileDesc *stack) { PRFileDesc *popped = PR_PopIOLayer(stack, identity); @@ -73,6 +74,7 @@ static PRFileDesc *PopLayer(PRFileDesc *stack) return stack; } /* PopLayer */ +#endif static void PR_CALLBACK Client(void *arg) { @@ -355,8 +357,8 @@ PRIntn main(PRIntn argc, char **argv) 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); + 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 layered test\n"); } diff --git a/pr/tests/lock.c b/pr/tests/lock.c index e5683171..6f4616dc 100644 --- a/pr/tests/lock.c +++ b/pr/tests/lock.c @@ -48,9 +48,11 @@ /* 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" @@ -60,7 +62,6 @@ #include "plstr.h" -#include <stdio.h> #include <stdlib.h> #if defined(XP_UNIX) @@ -72,21 +73,28 @@ #define printf PR_LogPrint extern void SetupMacPrintfLog(char *logFile); #endif -PRIntn failed_already=0; -PRIntn debug_mode; + +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; - PRUint32 loops; + PRInt32 loops; + PRUint32 contender; + PRUint32 contentious; PRIntervalTime overhead; PRIntervalTime interval; } LockContentious_t; typedef struct MonitorContentious_s { PRMonitor *ml; - PRUint32 loops; + PRInt32 loops; + PRUint32 contender; + PRUint32 contentious; PRIntervalTime overhead; PRIntervalTime interval; } MonitorContentious_t; @@ -137,6 +145,7 @@ static void PR_CALLBACK LockContender(void *arg) while (contention->loops-- > 0) { PR_Lock(contention->ml); + contention->contender+= 1; contention->overhead += contention->interval; PR_Sleep(contention->interval); PR_Unlock(contention->ml); @@ -150,7 +159,7 @@ static PRIntervalTime ContentiousLock(PRUint32 loops) LockContentious_t * contention; PRIntervalTime rv, overhead, timein = PR_IntervalNow(); - contention = (LockContentious_t *) PR_Calloc( 1, sizeof(LockContentious_t)); + contention = PR_NEWZAP(LockContentious_t); contention->loops = loops; contention->overhead = 0; contention->ml = PR_NewLock(); @@ -162,9 +171,10 @@ static PRIntervalTime ContentiousLock(PRUint32 loops) overhead = PR_IntervalNow() - timein; - while (contention->loops > 0) + while (contention->loops-- > 0) { PR_Lock(contention->ml); + contention->contentious+= 1; contention->overhead += contention->interval; PR_Sleep(contention->interval); PR_Unlock(contention->ml); @@ -175,6 +185,10 @@ static PRIntervalTime ContentiousLock(PRUint32 loops) 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 */ @@ -210,23 +224,23 @@ static PRIntervalTime NonContentiousMonitor(PRUint32 loops) static void PR_CALLBACK TryEntry(void *arg) { PRMonitor *ml = (PRMonitor*)arg; - if (debug_mode) printf("Reentrant thread created\n"); + if (debug_mode) PR_fprintf(std_err, "Reentrant thread created\n"); PR_EnterMonitor(ml); - if (debug_mode) printf("Reentrant thread acquired monitor\n"); + if (debug_mode) PR_fprintf(std_err, "Reentrant thread acquired monitor\n"); PR_ExitMonitor(ml); - if (debug_mode) printf("Reentrant thread released monitor\n"); + if (debug_mode) PR_fprintf(std_err, "Reentrant thread released monitor\n"); } /* TryEntry */ static PRIntervalTime ReentrantMonitor(PRUint32 loops) { - PRStatus status; + PRStatus status; PRThread *thread; PRMonitor *ml = PR_NewMonitor(); - if (debug_mode) printf("\nMonitor created for reentrant test\n"); + if (debug_mode) PR_fprintf(std_err, "\nMonitor created for reentrant test\n"); PR_EnterMonitor(ml); PR_EnterMonitor(ml); - if (debug_mode) printf("Monitor acquired twice\n"); + if (debug_mode) PR_fprintf(std_err, "Monitor acquired twice\n"); thread = PR_CreateThread( PR_USER_THREAD, TryEntry, ml, @@ -235,13 +249,13 @@ static PRIntervalTime ReentrantMonitor(PRUint32 loops) PR_Sleep(PR_SecondsToInterval(1)); PR_ExitMonitor(ml); - if (debug_mode) printf("Monitor released first time\n"); + if (debug_mode) PR_fprintf(std_err, "Monitor released first time\n"); PR_ExitMonitor(ml); - if (debug_mode) printf("Monitor released second time\n"); + if (debug_mode) PR_fprintf(std_err, "Monitor released second time\n"); status = PR_JoinThread(thread); - if (debug_mode) printf( + if (debug_mode) PR_fprintf(std_err, "Reentrant thread joined %s\n", (status == PR_SUCCESS) ? "successfully" : "in error"); @@ -255,6 +269,7 @@ static void PR_CALLBACK MonitorContender(void *arg) while (contention->loops-- > 0) { PR_EnterMonitor(contention->ml); + contention->contender+= 1; contention->overhead += contention->interval; PR_Sleep(contention->interval); PR_ExitMonitor(contention->ml); @@ -268,7 +283,7 @@ static PRUint32 ContentiousMonitor(PRUint32 loops) MonitorContentious_t * contention; PRIntervalTime rv, overhead, timein = PR_IntervalNow(); - contention = (MonitorContentious_t *) PR_Calloc(1, sizeof(MonitorContentious_t)); + contention = PR_NEWZAP(MonitorContentious_t); contention->loops = loops; contention->overhead = 0; contention->ml = PR_NewMonitor(); @@ -280,9 +295,10 @@ static PRUint32 ContentiousMonitor(PRUint32 loops) overhead = PR_IntervalNow() - timein; - while (contention->loops > 0) + while (contention->loops-- > 0) { PR_EnterMonitor(contention->ml); + contention->contentious+= 1; contention->overhead += contention->interval; PR_Sleep(contention->interval); PR_ExitMonitor(contention->ml); @@ -293,6 +309,10 @@ static PRUint32 ContentiousMonitor(PRUint32 loops) 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 */ @@ -317,6 +337,7 @@ static void PR_CALLBACK Contender(void *arg) while (contention->loops-- > 0) { PR_CEnterMonitor(contention); + contention->contender+= 1; contention->overhead += contention->interval; PR_Sleep(contention->interval); PR_CExitMonitor(contention); @@ -330,9 +351,8 @@ static PRIntervalTime ContentiousCMonitor(PRUint32 loops) MonitorContentious_t * contention; PRIntervalTime overhead, timein = PR_IntervalNow(); - contention = (MonitorContentious_t *) PR_Calloc(1, sizeof(MonitorContentious_t)); + contention = PR_NEWZAP(MonitorContentious_t); contention->ml = NULL; - contention->overhead = 0; contention->loops = loops; contention->interval = contention_interval; thread = PR_CreateThread( @@ -342,9 +362,10 @@ static PRIntervalTime ContentiousCMonitor(PRUint32 loops) overhead = PR_IntervalNow() - timein; - while (contention->loops > 0) + while (contention->loops-- > 0) { PR_CEnterMonitor(contention); + contention->contentious+= 1; contention->overhead += contention->interval; PR_Sleep(contention->interval); PR_CExitMonitor(contention); @@ -353,7 +374,13 @@ static PRIntervalTime ContentiousCMonitor(PRUint32 loops) timein = PR_IntervalNow(); status = PR_JoinThread(thread); overhead += (PR_IntervalNow() - timein); - return overhead + contention->overhead; + 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( @@ -381,12 +408,12 @@ static PRIntervalTime Test( accountable = duration - predicted; accountable -= overhead; elapsed = (PRFloat64)PR_IntervalToMicroseconds(accountable); - printf("%s:", msg); - while (spaces++ < 50) printf(" "); + PR_fprintf(PR_STDOUT, "%s:", msg); + while (spaces++ < 50) PR_fprintf(PR_STDOUT, " "); if ((PRInt32)accountable < 0) - printf("*****.** usecs/iteration\n"); + PR_fprintf(PR_STDOUT, "*****.** usecs/iteration\n"); else - printf("%8.2f usecs/iteration\n", elapsed/loops); + PR_fprintf(PR_STDOUT, "%8.2f usecs/iteration\n", elapsed/loops); } return duration; } /* Test */ @@ -410,14 +437,17 @@ int main(int argc, char **argv) Usage: lock [-d] [-l <num>] [-c <num>] */ PLOptStatus os; - PLOptState *opt = PL_CreateOptState(argc, argv, "dl:c:"); + 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 = 1; + debug_mode = PR_TRUE; + break; + case 'v': /* debug mode */ + verbosity = PR_TRUE; break; case 'l': /* number of loops */ loops = atoi(opt->value); @@ -441,16 +471,20 @@ int main(int argc, char **argv) #endif if (loops == 0) loops = 100; - if (debug_mode) printf("Lock: Using %d loops\n", loops); + 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) printf("Lock: Using %d cpu(s)\n", cpus); + 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) printf("\nLock: Using %d CPU(s)\n", 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); @@ -469,7 +503,10 @@ int main(int argc, char **argv) (void)ReentrantMonitor(loops); } - if (debug_mode) printf("%s: test %s\n", "Lock(mutex) test", ((rv) ? "passed" : "failed")); + if (debug_mode) + PR_fprintf( + std_err, "%s: test %s\n", "Lock(mutex) test", + ((rv) ? "passed" : "failed")); else { if (!rv) failed_already=1; @@ -477,12 +514,12 @@ int main(int argc, char **argv) if(failed_already) { - printf("FAIL\n"); + PR_fprintf(PR_STDOUT, "FAIL\n"); return 1; } else { - printf("PASS\n"); + PR_fprintf(PR_STDOUT, "PASS\n"); return 0; } diff --git a/pr/tests/many_cv.c b/pr/tests/many_cv.c index ae973655..1f964458 100644 --- a/pr/tests/many_cv.c +++ b/pr/tests/many_cv.c @@ -114,9 +114,7 @@ static PRIntn PR_CALLBACK RealMain( PRIntn argc, char **argv ) printf("PASS\n"); -#if defined(DEBUG) && defined(_PR_PTHREADS) PT_FPrintStats(err, "\nPThread Statistics\n"); -#endif /* defined(DEBUG) && defined(_PR_PTHREADS) */ return 0; } diff --git a/pr/tests/multiwait.c b/pr/tests/multiwait.c index be4ed6bb..4358b350 100644 --- a/pr/tests/multiwait.c +++ b/pr/tests/multiwait.c @@ -43,7 +43,6 @@ typedef struct Shared typedef enum Verbosity {silent, quiet, chatty, noisy} Verbosity; -static PRUint32 identity = 0; static PRFileDesc *debug = NULL; static PRInt32 desc_allocated = 0; static PRUint16 default_port = 12273; @@ -113,7 +112,7 @@ static PRRecvWait *CreateRecvWait(PRFileDesc *fd, PRIntervalTime timeout) return desc_out; } /* CreateRecvWait */ -static void DestroyRecvWait(Shared *shared, PRRecvWait *desc_out) +static void DestroyRecvWait(PRRecvWait *desc_out) { if (verbosity > chatty) PrintRecvDesc(desc_out, "Destroying"); @@ -134,7 +133,7 @@ static void CancelGroup(Shared *shared) do { desc_out = PR_CancelWaitGroup(shared->group); - if (NULL != desc_out) DestroyRecvWait(shared, desc_out); + if (NULL != desc_out) DestroyRecvWait(desc_out); } while (NULL != desc_out); MW_ASSERT(0 == desc_allocated); @@ -298,7 +297,7 @@ static void PR_CALLBACK SomeOpsThread(void *arg) if (NULL == desc_out) { MW_ASSERT(PR_PENDING_INTERRUPT_ERROR == PR_GetError()); - if (verbosity > quiet) PrintRecvDesc(desc_out, "Aborted"); + if (verbosity > quiet) PR_fprintf(debug, "Aborted\n"); break; } MW_ASSERT(PR_MW_TIMEOUT == desc_out->outcome); @@ -422,9 +421,6 @@ static void PR_CALLBACK ServiceThread(void *arg) case PR_MW_SUCCESS: { PR_AtomicIncrement(&ops_done); - if (verbosity > quiet) - PR_fprintf( - debug, "%s: Servicing %u\n", shared->title, ops_done); if (verbosity > chatty) PrintRecvDesc(desc_out, "Service ready"); rv = ServiceRequest(shared, desc_out); @@ -445,10 +441,40 @@ static void PR_CALLBACK ServiceThread(void *arg) } } while (PR_SUCCESS == rv); - if (NULL != desc_out) DestroyRecvWait(shared, desc_out); + 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) { @@ -534,7 +560,7 @@ static void RealOneGroupIO(Shared *shared) */ PRStatus rv; PRIntn index; - PRThread *server_thread, **client_thread; + PRThread *server_thread, *enumeration_thread, **client_thread; if (verbosity > quiet) PR_fprintf(debug, "%s: creating server_thread\n", shared->title); @@ -545,6 +571,14 @@ static void RealOneGroupIO(Shared *shared) 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); @@ -572,6 +606,13 @@ static void RealOneGroupIO(Shared *shared) } 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); @@ -598,7 +639,7 @@ static void RunThisOne( static Verbosity ChangeVerbosity(Verbosity verbosity, PRIntn delta) { PRIntn verbage = (PRIntn)verbosity; - return (Verbosity)(verbage += 1); + return (Verbosity)(verbage += delta); } /* ChangeVerbosity */ PRIntn main(PRIntn argc, char **argv) diff --git a/pr/tests/nbconn.c b/pr/tests/nbconn.c index 372a8e78..b206f991 100644 --- a/pr/tests/nbconn.c +++ b/pr/tests/nbconn.c @@ -38,6 +38,7 @@ */ #include "nspr.h" +#include "plgetopt.h" #include <stdio.h> #ifdef XP_MAC @@ -46,21 +47,61 @@ extern void SetupMacPrintfLog(char *logFile); static char *hosts[4] = {"cynic", "warp", "gandalf", "neon"}; #endif +#define SERVER_MAX_BIND_COUNT 100 +#define DATA_BUF_SIZE 256 +#define TCP_SERVER_PORT 10000 + +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; - PRFileDesc *sock; PRPollDesc pd; PRStatus rv; PRSocketOptionData optData; - PRIntn n; - + const char *hostname; + PRIntn default_case, n, bytes_read, bytes_sent; + PRInt32 failed_already = 0; #ifdef XP_MAC int index; PRIntervalTime timeout; +#endif + + /* + * -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); + +#ifdef XP_MAC SetupMacPrintfLog("nbconn.log"); for (index=0; index<4; index++) { argv[1] = hosts[index]; @@ -69,90 +110,473 @@ int main(int argc, char **argv) timeout = PR_SecondsToInterval(10UL); #endif + PR_STDIO_INIT(); #ifndef XP_MAC - if (argc != 2) { - fprintf(stderr, "Usage: nbconn <hostname>\n"); - exit(1); - } + if (hostname) + default_case = 0; + else + default_case = 1; #endif - if (PR_GetHostByName(argv[1], buf, sizeof(buf), &he) == PR_FAILURE) { - printf( "Unknown host: %s\n", buf); - 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"); - } + 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 + * non-existent port and expects to get an error + */ + rv = connection_success_test(); + if (rv == 0) + rv = connection_failure_test(); + return rv; + } else { + PRFileDesc *sock; - pd.fd = sock; - pd.in_flags = PR_POLL_WRITE | PR_POLL_EXCEPT; + 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; #ifndef XP_MAC - n = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT); + n = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT); #else - n = PR_Poll(&pd, 1, timeout); + n = PR_Poll(&pd, 1, timeout); #endif - 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 (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"); - /* Mac and Win16 have trouble printing to the console. */ + if (PR_GetConnectStatus(&pd) == PR_SUCCESS) { + printf("PR_GetConnectStatus: connect succeeded\n"); + /* Mac and Win16 have trouble printing to the console. */ #if !defined(XP_MAC) && !defined(WIN16) - 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); - } + 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); + } #endif - } 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); + } 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); #ifdef XP_MAC - } /* end of for loop */ + } /* end of for loop */ +#endif + 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; + + /* + * 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; + } + } else { + PR_ASSERT(rv == PR_SUCCESS); + fprintf(stderr,"Error - PR_Connect succeeded, expected to fail\n"); + 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; +#ifndef XP_MAC + n = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT); +#else + n = PR_Poll(&pd, 1, timeout); +#endif + if (n == -1) { + fprintf(stderr,"Error - PR_Poll failed: (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + failed_already=1; + goto def_exit; + } + if (pd.out_flags != PR_POLL_WRITE) { + fprintf(stderr,"Error - PR_Poll returned invalid outflags: 0x%x\n", + pd.out_flags); + 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 non-existent 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; + } + 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; +#ifndef XP_MAC + n = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT); +#else + n = PR_Poll(&pd, 1, timeout); #endif + if (n == -1) { + fprintf(stderr,"Error - PR_Poll failed: (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + failed_already=1; + goto def_exit; + } + if (pd.out_flags != PR_POLL_WRITE) { + fprintf(stderr,"Error - PR_Poll returned invalid outflags: 0x%x\n", + pd.out_flags); + 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; - printf( "PASS\n"); - return 0; } diff --git a/pr/tests/nblayer.c b/pr/tests/nblayer.c index 2c0ffd67..b14073a1 100644 --- a/pr/tests/nblayer.c +++ b/pr/tests/nblayer.c @@ -103,20 +103,24 @@ static void PR_CALLBACK Client(void *arg) 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) break; /* if not 1, then we're dead */ - rv = PR_GetConnectStatus(&polldesc); - if (PR_FAILURE == rv) - { - if (PR_IN_PROGRESS_ERROR != PR_GetError()) break; - } - } + 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_ASSERT(!"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); @@ -126,24 +130,29 @@ static void PR_CALLBACK Client(void *arg) for (mits = 0; mits < minor_iterations; ++mits) { bytes_sent = 0; - if (verbosity > chatty) + 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 (0 < ready) - { - bytes_sent += ready; - } + 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) break; /* if not 1, then we're dead */ + if ((1 != ready) /* if not 1, then we're dead */ + || (0 == (polldesc.in_flags & polldesc.out_flags))) + { PR_ASSERT(!"Whoa!"); break; } } else break; } while (bytes_sent < sizeof(buffer)); @@ -152,20 +161,26 @@ static void PR_CALLBACK Client(void *arg) 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 (0 < ready) - { - bytes_read += ready; - } + 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) break; /* if not 1, then we're dead */ + if ((1 != ready) /* if not 1, then we're dead */ + || (0 == (polldesc.in_flags & polldesc.out_flags))) + { PR_ASSERT(!"Whoa!"); break; } } else break; } while (bytes_read < bytes_sent); @@ -200,14 +215,20 @@ static void PR_CALLBACK Server(void *arg) 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; + polldesc.in_flags = PR_POLL_READ | PR_POLL_EXCEPT; ready = PR_Poll(&polldesc, 1, PR_INTERVAL_NO_TIMEOUT); - if (1 != ready) break; /* if not 1, then we're dead */ + if ((1 != ready) /* if not 1, then we're dead */ + || (0 == (polldesc.in_flags & polldesc.out_flags))) + { PR_ASSERT(!"Whoa!"); break; } } } while (NULL == service); PR_ASSERT(NULL != service); @@ -220,20 +241,25 @@ static void PR_CALLBACK Server(void *arg) 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 (0 < ready) - { - bytes_read += ready; - } + 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) break; /* if not 1, then we're dead */ + if ((1 != ready) /* if not 1, then we're dead */ + || (0 == (polldesc.in_flags & polldesc.out_flags))) + { PR_ASSERT(!"Whoa!"); break; } } else break; } while (bytes_read < sizeof(buffer)); @@ -260,7 +286,9 @@ static void PR_CALLBACK Server(void *arg) polldesc.out_flags = 0; polldesc.in_flags = PR_POLL_WRITE; ready = PR_Poll(&polldesc, 1, PR_INTERVAL_NO_TIMEOUT); - if (1 != ready) break; /* if not 1, then we're dead */ + if ((1 != ready) /* if not 1, then we're dead */ + || (0 == (polldesc.in_flags & polldesc.out_flags))) + { PR_ASSERT(!"Whoa!"); break; } } else break; } while (bytes_sent < bytes_read); @@ -331,7 +359,6 @@ static PRInt32 PR_CALLBACK MyRecv( { char *b; PRInt32 rv; - PRPollDesc polldesc; PRFileDesc *lo = fd->lower; PRFilePrivate *mine = (PRFilePrivate*)fd->secret; diff --git a/pr/tests/op_filok.c b/pr/tests/op_filok.c index dc17efea..ae540ac7 100644 --- a/pr/tests/op_filok.c +++ b/pr/tests/op_filok.c @@ -42,31 +42,42 @@ #else #endif -static PRFileDesc *t1; +/* + * The name of a file that is guaranteed to exist + * on every machine of a particular OS. + */ +#ifdef XP_UNIX +#define EXISTING_FILENAME "/bin/sh" +#elif defined(WIN32) +#define EXISTING_FILENAME "c:/boot.ini" +#else +#error "Unknown OS" +#endif -PRIntn error_code; +static PRFileDesc *t1; int main(int argc, char **argv) { - #ifdef XP_MAC SetupMacPrintfLog("pr_open_re.log"); #endif - - PR_STDIO_INIT(); - t1 = PR_Open("/usr/tmp/ttools/nspr20/err03.tmp", PR_TRUNCATE | PR_RDWR, 0666); + t1 = PR_Open(EXISTING_FILENAME, PR_RDONLY, 0666); if (t1 == NULL) { - if (PR_GetError() == PR_FILE_NOT_FOUND_ERROR) { - printf ("error code is %d \n", PR_GetError()); - printf ("File should be found\n"); + printf ("error code is %d \n", PR_GetError()); + printf ("File %s should be found\n", + EXISTING_FILENAME); + 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; } } - else { - printf ("Test passed \n"); - return 0; - } } diff --git a/pr/tests/op_noacc.c b/pr/tests/op_noacc.c index c528dc75..b45fce2e 100644 --- a/pr/tests/op_noacc.c +++ b/pr/tests/op_noacc.c @@ -54,6 +54,10 @@ int main(int argc, char **argv) SetupMacPrintfLog("pr_open_re.log"); #endif +#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(); diff --git a/pr/tests/op_nofil.c b/pr/tests/op_nofil.c index c38063ff..3cb3adef 100644 --- a/pr/tests/op_nofil.c +++ b/pr/tests/op_nofil.c @@ -43,31 +43,38 @@ #else #endif +/* + * A file name that cannot exist + */ +#define NO_SUCH_FILE "/no/such/file.tmp" + static PRFileDesc *t1; -PRIntn error_code; int main(int argc, char **argv) { - #ifdef XP_MAC SetupMacPrintfLog("pr_open_re.log"); #endif - - PR_STDIO_INIT(); - t1 = PR_Open("/usr/tmp/err02.tmp", PR_RDWR, 0666); - if (t1 == NULL) + t1 = PR_Open(NO_SUCH_FILE, PR_RDONLY, 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; + 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/pr/tests/parent.c b/pr/tests/parent.c index 4e82b8b0..d5fef9ec 100644 --- a/pr/tests/parent.c +++ b/pr/tests/parent.c @@ -26,6 +26,7 @@ #include "prprf.h" #include "prinit.h" #include "prproces.h" +#include "prinrval.h" typedef struct Child { @@ -44,6 +45,7 @@ PRIntn main (PRIntn argc, char **argv) { PRStatus rv; PRInt32 test_status = 1; + PRIntervalTime t_start, t_elapsed; PRFileDesc *debug = NULL; Child *child = PR_NEWZAP(Child); @@ -83,14 +85,22 @@ PRIntn main (PRIntn argc, char **argv) child->attr, PR_StandardError, PR_GetSpecialFD(PR_StandardError)); + t_start = PR_IntervalNow(); child->process = PR_CreateProcess( child->name, argv, NULL, child->attr); + t_elapsed = (PRIntervalTime) (PR_IntervalNow() - t_start); 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) { diff --git a/pr/tests/perf.c b/pr/tests/perf.c index 5928052f..b6785d75 100644 --- a/pr/tests/perf.c +++ b/pr/tests/perf.c @@ -67,6 +67,26 @@ static void DLLProcedureCall(void) } } +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; @@ -399,6 +419,8 @@ int main(int argc, char **argv) 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"); @@ -420,6 +442,8 @@ int main(int argc, char **argv) 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"); diff --git a/pr/tests/poll_nm.c b/pr/tests/poll_nm.c index a8995b3b..ab5c5286 100644 --- a/pr/tests/poll_nm.c +++ b/pr/tests/poll_nm.c @@ -89,7 +89,7 @@ clientThreadFunc(void *arg) 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", addr.inet.ip); + PR_snprintf(buf, sizeof(buf), "%hu", port); for (i = 0; i < NUM_ITERATIONS; i++) { sock = PR_NewTCPSocket(); diff --git a/pr/tests/pollable.c b/pr/tests/pollable.c new file mode 100644 index 00000000..f31d8a93 --- /dev/null +++ b/pr/tests/pollable.c @@ -0,0 +1,273 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +/* + * 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_fprintf(PR_STDOUT, "PASSED\n"); + return 0; +} diff --git a/pr/tests/prftest2.c b/pr/tests/prftest2.c index b5322888..c3239905 100644 --- a/pr/tests/prftest2.c +++ b/pr/tests/prftest2.c @@ -105,6 +105,6 @@ int main( int argc, char *argv[]) else { printf("PASSED\n"); - return 1; + return 0; } } diff --git a/pr/tests/priotest.c b/pr/tests/priotest.c index cdc76953..f9df1528 100644 --- a/pr/tests/priotest.c +++ b/pr/tests/priotest.c @@ -42,7 +42,7 @@ #include <stdio.h> #include <stdlib.h> -#define DEFAULT_DURATION 20 +#define DEFAULT_DURATION 5 static PRBool failed = PR_FALSE; static PRIntervalTime oneSecond; @@ -131,7 +131,7 @@ static void RudimentaryTests(void) } /* RudimentataryTests */ -static void CreateThreads(PRInt32 *lowCount, PRInt32 *highCount) +static void CreateThreads(PRUint32 *lowCount, PRUint32 *highCount) { (void)PR_CreateThread( PR_USER_THREAD, Low, lowCount, PR_PRIORITY_LOW, diff --git a/pr/tests/provider.c b/pr/tests/provider.c new file mode 100644 index 00000000..49428b3a --- /dev/null +++ b/pr/tests/provider.c @@ -0,0 +1,1356 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +/* + * + * 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 + +#ifdef XP_MAC +#include "prlog.h" +#define printf PR_LogPrint +#endif + +/* +** This is the beginning of the test +*/ + +#define RECV_FLAGS 0 +#define SEND_FLAGS 0 +#define BUFFER_SIZE 1024 +#define DEFAULT_BACKLOG 5 +#define DEFAULT_PORT 12848 +#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); +#if DEBUG + PR_Assert(s, file, ln); +#endif +} /* _MW_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), "%T", &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_CurrentThread(); + 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_CurrentThread())); + 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_CurrentThread(), 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_CurrentThread(); + 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_CurrentThread())); + 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) && !defined(_PR_DCETHREADS) +#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) && !defined(_PR_DCETHREADS) */ + +#if defined(IRIX) && !defined(_PR_PTHREADS) +#include <sys/types.h> +#include <sys/prctl.h> +static void sproc_start(void *arg, PRSize size) +{ + StartObject *so = (StartObject*)arg; + StartFn start = so->start; + void *data = so->arg; + PR_Free(so); + start(data); +} /* sproc_start */ +#endif /* defined(IRIX) && !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) && !defined(_PR_DCETHREADS) + rv = PR_SUCCESS; + break; +#endif /* defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS) */ + 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_UNJOINABLE_THREAD, 0); + rv = (NULL == thread) ? PR_FAILURE : PR_SUCCESS; + } + break; + case thread_pthread: +#if defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS) + { + 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 = PTHREAD_ATTR_INIT(&tattr); + PR_ASSERT(0 == rv); + + rv = pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED); + PR_ASSERT(0 == rv); + +#if !defined(LINUX) + rv = pthread_attr_setstacksize(&tattr, 64 * 1024); + PR_ASSERT(0 == rv); +#endif + + rv = PTHREAD_CREATE(&id, tattr, pthread_start, start_object); + (void)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) && !defined(_PR_DCETHREADS) */ + break; + + case thread_sproc: +#if defined(IRIX) && !defined(_PR_PTHREADS) + { + PRInt32 pid; + StartObject *start_object; + start_object = PR_NEW(StartObject); + PR_ASSERT(NULL != start_object); + start_object->start = start; + start_object->arg = arg; + pid = sprocsp( + sproc_start, PR_SALL, start_object, NULL, 64 * 1024); + rv = (0 < pid) ? PR_SUCCESS : PR_FAILURE; + } +#else + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + rv = PR_FAILURE; +#endif /* defined(IRIX) && !defined(_PR_PTHREADS) */ + 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 */ + 0U, /*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_CurrentThread(), 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_CurrentThread(); + + 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_CurrentThread(), 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_CurrentThread(); + + server->listener = PR_Socket(domain, SOCK_STREAM, protocol); + + 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"); +#ifdef _PR_INET6 + PR_fprintf(debug_out, "\t-6 Use IPv6 (IPv4)\n"); +#endif /* _PR_INET6 */ + 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 */ + +PRIntn main(PRIntn 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; + + /* + * -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"); + + 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; +#ifdef _PR_INET6 + case '6': /* Use IPv6 */ + domain = AF_INET6; + PR_SetIPv6Enable(PR_TRUE); + break; +#endif /* _PR_INET6 */ + 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_CurrentThread()); + + cltsrv_log_file = PR_NewLogModule("cltsrv_log"); + MY_ASSERT(NULL != cltsrv_log_file); + boolean = PR_SetLogFile("cltsrv.log"); + MY_ASSERT(boolean); + +#ifdef XP_MAC + debug_mode = PR_TRUE; +#endif + + if (serverIsLocal) + { + /* Establish the server */ + TEST_LOG( + cltsrv_log_file, TEST_LOG_INFO, + ("main(0x%p): starting server\n", PR_CurrentThread())); + + 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_CurrentThread())); + + 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_CurrentThread())); + + 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_CurrentThread(), 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_CurrentThread(), 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_CurrentThread())); + 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_CurrentThread(), execution)); + + WaitForCompletion(execution); + + TimeOfDayMessage("Shutting down", PR_CurrentThread()); + + 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_CurrentThread(), 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_CurrentThread(), 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_CurrentThread(), 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_CurrentThread(), 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_CurrentThread())); + + PT_FPrintStats(debug_out, "\nPThread Statistics\n"); + + TimeOfDayMessage("Test exiting at", PR_CurrentThread()); + return 0; +} /* main */ + +/* cltsrv.c */ diff --git a/pr/tests/sel_spd.c b/pr/tests/sel_spd.c index f4ce1483..b0033567 100644 --- a/pr/tests/sel_spd.c +++ b/pr/tests/sel_spd.c @@ -51,6 +51,9 @@ typedef struct timer_slot_t { unsigned long requests; } timer_slot_t; +static long _iterations = 5; +static long _client_data = 8192; + #if defined(XP_MAC) /* * Mac does not scale well specially the requirement for thread stack @@ -58,22 +61,18 @@ typedef struct timer_slot_t { * memory and not be able to allocate thread stack or client/server data * buffer. */ +static long _server_data = (8*1024); static long _threads_max = 10, _threads = 10; -static long _iterations = 50; -static long _client_data = 8192; -static long _server_data = 8192; #else -static long _threads_max = 100, _threads = 100; -static long _iterations = 1000; -static long _client_data = 8192; static long _server_data = (128*1024); +static long _threads_max = 100, _threads = 100; #endif -static long _thread_exit_count; +static int verbose=0; static PRMonitor *exit_cv; +static long _thread_exit_count; static timer_slot_t *timer_data; static PRThreadScope scope1, scope2; -static int verbose=0; void tally_results(int); diff --git a/pr/tests/socket.c b/pr/tests/socket.c index 33ce32bb..770d5f71 100644 --- a/pr/tests/socket.c +++ b/pr/tests/socket.c @@ -373,7 +373,7 @@ UDP_Server(void *arg) PRFileDesc *sockfd; buffer *in_buf; PRNetAddr netaddr; - PRInt32 bytes, i, rv; + PRInt32 bytes, i, rv = 0; bytes = sp->datalen; @@ -1046,7 +1046,6 @@ TransmitFile_Client(void *arg) fprintf(stderr, "prsocket_test: TransmitFile_Client ERROR - large file data corruption\n"); failed_already=1; - return; } #endif PR_DELETE(small_buf); @@ -1518,8 +1517,8 @@ done: PR_DELETE(buf); } #ifdef XP_UNIX - munmap(small_file_addr, SMALL_FILE_SIZE); - munmap(large_file_addr, LARGE_FILE_SIZE); + 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); diff --git a/pr/tests/stack.c b/pr/tests/stack.c new file mode 100644 index 00000000..d48e3ddb --- /dev/null +++ b/pr/tests/stack.c @@ -0,0 +1,266 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + + +/* + * + * 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 4 +/* + * 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; +} stack_data; + +static void stackop(void *arg); + +static int _debug_on; + +PRFileDesc *output; +PRFileDesc *errhandle; + +PRIntn main(PRIntn 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; + PRThread **threads; + stack_data *thread_args; + + 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': /* data count */ + data_cnt = 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].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; + DataRecord *Items, *Item; + PRStack *list1, *list2; + PRStackElem *node; + stack_data *arg = (stack_data *) thread_arg; + + val = arg->initial_data_value; + cnt = arg->data_cnt; + 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++; + } + + /* + * 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/pr/tests/switch.c b/pr/tests/switch.c index 131260fc..878d7d15 100644 --- a/pr/tests/switch.c +++ b/pr/tests/switch.c @@ -63,14 +63,14 @@ static void Help(void) debug_out = PR_STDOUT; PR_fprintf( - debug_out, "Usage: >./switch [-d] [-c n] [-t n] [-T n] [-G]\n"); + 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 n\tglobal threads only (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 */ diff --git a/pr/tests/testfile.c b/pr/tests/testfile.c index d492a0ff..2f5129d4 100644 --- a/pr/tests/testfile.c +++ b/pr/tests/testfile.c @@ -44,7 +44,6 @@ extern void SetupMacPrintfLog(char *logFile); PRLock *lock; PRMonitor *mon; -PRMonitor *mon2; PRInt32 count; int thread_count; @@ -108,11 +107,12 @@ int offset, len; } DPRINTF(("Write out_buf[0] = 0x%x\n",(*((int *) buf)))); PR_Close(fd_file); + PR_DELETE(fp); - PR_EnterMonitor(mon2); + PR_EnterMonitor(mon); --thread_count; - PR_Notify(mon2); - PR_ExitMonitor(mon2); + PR_Notify(mon); + PR_ExitMonitor(mon); } static void PR_CALLBACK File_Read(void *arg) @@ -143,11 +143,12 @@ int offset, len; } DPRINTF(("Read in_buf[0] = 0x%x\n",(*((int *) buf)))); PR_Close(fd_file); + PR_DELETE(fp); - PR_EnterMonitor(mon2); + PR_EnterMonitor(mon); --thread_count; - PR_Notify(mon2); - PR_ExitMonitor(mon2); + PR_Notify(mon); + PR_ExitMonitor(mon); } @@ -295,6 +296,7 @@ static PRInt32 PR_CALLBACK FileTest(void) PRDir *fd_dir; int i, offset, len; PRThread *t; +PRThreadScope scope; File_Rdwr_Param *fparamp; /* @@ -334,12 +336,7 @@ File_Rdwr_Param *fparamp; */ offset = 0; len = CHUNK_SIZE; - mon2 = PR_NewMonitor(); - if (mon2 == NULL) { - printf("testfile: PR_NewMonitor failed\n"); - return -1; - } - PR_EnterMonitor(mon2); + PR_EnterMonitor(mon); for (i = 0; i < NUM_RDWR_THREADS; i++) { fparamp = PR_NEW(File_Rdwr_Param); if (fparamp == NULL) { @@ -356,27 +353,24 @@ File_Rdwr_Param *fparamp; * Create LOCAL and GLOBAL Threads, alternately */ if (i % 1) - t = PR_CreateThread(PR_USER_THREAD, - File_Write, (void *)fparamp, - PR_PRIORITY_NORMAL, - PR_GLOBAL_THREAD, - PR_UNJOINABLE_THREAD, - 0); + scope = PR_GLOBAL_THREAD; else - t = PR_CreateThread(PR_USER_THREAD, - File_Write, (void *)fparamp, - PR_PRIORITY_NORMAL, - PR_LOCAL_THREAD, - PR_UNJOINABLE_THREAD, - 0); + scope = PR_LOCAL_THREAD; + + t = PR_CreateThread(PR_USER_THREAD, + File_Write, (void *)fparamp, + PR_PRIORITY_NORMAL, + scope, + PR_UNJOINABLE_THREAD, + 0); offset += len; } thread_count = i; /* Wait for writer threads to exit */ while (thread_count) { - PR_Wait(mon2, PR_INTERVAL_NO_TIMEOUT); + PR_Wait(mon, PR_INTERVAL_NO_TIMEOUT); } - PR_ExitMonitor(mon2); + PR_ExitMonitor(mon); /* @@ -384,7 +378,7 @@ File_Rdwr_Param *fparamp; */ offset = 0; len = CHUNK_SIZE; - PR_EnterMonitor(mon2); + PR_EnterMonitor(mon); for (i = 0; i < NUM_RDWR_THREADS; i++) { fparamp = PR_NEW(File_Rdwr_Param); if (fparamp == NULL) { @@ -400,19 +394,16 @@ File_Rdwr_Param *fparamp; * Create LOCAL and GLOBAL Threads, alternately */ if (i % 1) - t = PR_CreateThread(PR_USER_THREAD, - File_Read, (void *)fparamp, - PR_PRIORITY_NORMAL, - PR_LOCAL_THREAD, - PR_UNJOINABLE_THREAD, - 0); + scope = PR_LOCAL_THREAD; else - t = PR_CreateThread(PR_USER_THREAD, - File_Read, (void *)fparamp, - PR_PRIORITY_NORMAL, - PR_GLOBAL_THREAD, - PR_UNJOINABLE_THREAD, - 0); + scope = PR_GLOBAL_THREAD; + + t = PR_CreateThread(PR_USER_THREAD, + File_Read, (void *)fparamp, + PR_PRIORITY_NORMAL, + scope, + PR_UNJOINABLE_THREAD, + 0); offset += len; if ((offset + len) > BUF_DATA_SIZE) break; @@ -421,9 +412,9 @@ File_Rdwr_Param *fparamp; /* Wait for reader threads to exit */ while (thread_count) { - PR_Wait(mon2, PR_INTERVAL_NO_TIMEOUT); + PR_Wait(mon, PR_INTERVAL_NO_TIMEOUT); } - PR_ExitMonitor(mon2); + PR_ExitMonitor(mon); if (memcmp(in_buf->data, out_buf->data, offset) != 0) { printf("File Test failed: file data corrupted\n"); @@ -759,7 +750,7 @@ HANDLE hfile; * Test file and directory NSPR APIs */ -void main(int argc, char **argv) +int main(int argc, char **argv) { #ifdef XP_UNIX int opt; @@ -784,7 +775,11 @@ void main(int argc, char **argv) SetupMacPrintfLog("testfile.log"); #endif - mon2 = PR_NewMonitor(); + mon = PR_NewMonitor(); + if (mon == NULL) { + printf("testfile: PR_NewMonitor failed\n"); + exit(2); + } if (FileTest() < 0) { printf("File Test failed\n"); @@ -798,5 +793,7 @@ void main(int argc, char **argv) } printf("Dir Test passed\n"); + PR_DestroyMonitor(mon); PR_Cleanup(); + return 0; } diff --git a/pr/tests/tpd.c b/pr/tests/tpd.c index 9afce87c..786948e4 100644 --- a/pr/tests/tpd.c +++ b/pr/tests/tpd.c @@ -21,6 +21,7 @@ ** Description: Exercising the thread private data bailywick. */ +#include "prmem.h" #include "prinit.h" #include "prlog.h" #include "prprf.h" @@ -42,18 +43,20 @@ static PRBool should = PR_TRUE; static PRBool did = PR_TRUE; static PRFileDesc *fout = NULL; -static void PrintProgress(void) +static void PrintProgress(PRIntn line) { + failed = failed || (should && !did); + failed = failed || (!should && did); if (debug > 0) { #if defined(WIN16) printf( - "Destructor should %s have been called and was%s\n", - ((should) ? "" : " NOT"), ((did) ? "" : " NOT")); + "@ line %d destructor should%s have been called and was%s\n", + line, ((should) ? "" : " NOT"), ((did) ? "" : " NOT")); #else PR_fprintf( - fout, "Destructor should %s have been called and was%s\n", - ((should) ? "" : " NOT"), ((did) ? "" : " NOT")); + fout, "@ line %d destructor should%s have been called and was%s\n", + line, ((should) ? "" : " NOT"), ((did) ? "" : " NOT")); #endif } } /* PrintProgress */ @@ -70,10 +73,15 @@ static void MyAssert(const char *expr, const char *file, PRIntn line) static void PR_CALLBACK Destructor(void *data) { + MY_ASSERT(NULL != data); if (should) did = PR_TRUE; else failed = PR_TRUE; - MY_ASSERT(NULL != data); - if (debug > 0) MyAssert((const char*)data, __FILE__, __LINE__); + /* + * 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) @@ -91,24 +99,24 @@ static void PR_CALLBACK Thread(void *null) pd = PR_GetThreadPrivate(key[keys]); MY_ASSERT(NULL == pd); } - PrintProgress(); + PrintProgress(__LINE__); did = should = PR_FALSE; for (keys = 0; keys < 4; ++keys) { - rv = PR_SetThreadPrivate(keys, key_string[keys]); + rv = PR_SetThreadPrivate(key[keys], key_string[keys]); MY_ASSERT(PR_SUCCESS == rv); } - PrintProgress(); + PrintProgress(__LINE__); #if !defined(DEBUG) did = should = PR_FALSE; for (keys = 4; keys < 8; ++keys) { - rv = PR_SetThreadPrivate(keys, key_string[keys]); + rv = PR_SetThreadPrivate(key[keys], key_string[keys]); MY_ASSERT(PR_FAILURE == rv); } - PrintProgress(); + PrintProgress(__LINE__); #endif did = PR_FALSE; should = PR_TRUE; @@ -117,7 +125,7 @@ static void PR_CALLBACK Thread(void *null) rv = PR_SetThreadPrivate(key[keys], key_string[keys]); MY_ASSERT(PR_SUCCESS == rv); } - PrintProgress(); + PrintProgress(__LINE__); did = PR_FALSE; should = PR_TRUE; for (keys = 0; keys < 4; ++keys) @@ -125,7 +133,7 @@ static void PR_CALLBACK Thread(void *null) rv = PR_SetThreadPrivate(key[keys], NULL); MY_ASSERT(PR_SUCCESS == rv); } - PrintProgress(); + PrintProgress(__LINE__); did = should = PR_FALSE; for (keys = 0; keys < 4; ++keys) @@ -133,7 +141,7 @@ static void PR_CALLBACK Thread(void *null) rv = PR_SetThreadPrivate(key[keys], NULL); MY_ASSERT(PR_SUCCESS == rv); } - PrintProgress(); + PrintProgress(__LINE__); did = should = PR_FALSE; for (keys = 8; keys < 127; ++keys) @@ -141,7 +149,7 @@ static void PR_CALLBACK Thread(void *null) rv = PR_SetThreadPrivate(key[keys], "EXTENSION"); MY_ASSERT(PR_SUCCESS == rv); } - PrintProgress(); + PrintProgress(__LINE__); did = PR_FALSE; should = PR_TRUE; for (keys = 8; keys < 127; ++keys) @@ -149,7 +157,7 @@ static void PR_CALLBACK Thread(void *null) rv = PR_SetThreadPrivate(key[keys], NULL); MY_ASSERT(PR_SUCCESS == rv); } - PrintProgress(); + PrintProgress(__LINE__); did = should = PR_FALSE; for (keys = 8; keys < 127; ++keys) @@ -157,6 +165,17 @@ static void PR_CALLBACK Thread(void *null) 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) @@ -177,7 +196,7 @@ static PRIntn PR_CALLBACK Tpd(PRIntn argc, char **argv) rv = PR_NewThreadPrivateIndex(&key[keys], Destructor); MY_ASSERT(PR_SUCCESS == rv); } - PrintProgress(); + PrintProgress(__LINE__); did = should = PR_FALSE; for (keys = 0; keys < 8; ++keys) @@ -185,24 +204,24 @@ static PRIntn PR_CALLBACK Tpd(PRIntn argc, char **argv) pd = PR_GetThreadPrivate(key[keys]); MY_ASSERT(NULL == pd); } - PrintProgress(); + PrintProgress(__LINE__); did = should = PR_FALSE; for (keys = 0; keys < 4; ++keys) { - rv = PR_SetThreadPrivate(keys, key_string[keys]); + rv = PR_SetThreadPrivate(key[keys], key_string[keys]); MY_ASSERT(PR_SUCCESS == rv); } - PrintProgress(); + PrintProgress(__LINE__); #if !defined(DEBUG) did = should = PR_FALSE; for (keys = 4; keys < 8; ++keys) { - rv = PR_SetThreadPrivate(keys, key_string[keys]); + rv = PR_SetThreadPrivate(key[keys], key_string[keys]); MY_ASSERT(PR_FAILURE == rv); } - PrintProgress(); + PrintProgress(__LINE__); #endif did = PR_FALSE; should = PR_TRUE; @@ -211,7 +230,7 @@ static PRIntn PR_CALLBACK Tpd(PRIntn argc, char **argv) rv = PR_SetThreadPrivate(key[keys], key_string[keys]); MY_ASSERT(PR_SUCCESS == rv); } - PrintProgress(); + PrintProgress(__LINE__); did = PR_FALSE; should = PR_TRUE; for (keys = 0; keys < 4; ++keys) @@ -219,7 +238,7 @@ static PRIntn PR_CALLBACK Tpd(PRIntn argc, char **argv) rv = PR_SetThreadPrivate(key[keys], NULL); MY_ASSERT(PR_SUCCESS == rv); } - PrintProgress(); + PrintProgress(__LINE__); did = should = PR_FALSE; for (keys = 0; keys < 4; ++keys) @@ -227,7 +246,7 @@ static PRIntn PR_CALLBACK Tpd(PRIntn argc, char **argv) rv = PR_SetThreadPrivate(key[keys], NULL); MY_ASSERT(PR_SUCCESS == rv); } - PrintProgress(); + PrintProgress(__LINE__); did = should = PR_FALSE; for (keys = 8; keys < 127; ++keys) @@ -237,7 +256,7 @@ static PRIntn PR_CALLBACK Tpd(PRIntn argc, char **argv) rv = PR_SetThreadPrivate(key[keys], "EXTENSION"); MY_ASSERT(PR_SUCCESS == rv); } - PrintProgress(); + PrintProgress(__LINE__); did = PR_FALSE; should = PR_TRUE; for (keys = 8; keys < 127; ++keys) @@ -245,7 +264,7 @@ static PRIntn PR_CALLBACK Tpd(PRIntn argc, char **argv) rv = PR_SetThreadPrivate(key[keys], NULL); MY_ASSERT(PR_SUCCESS == rv); } - PrintProgress(); + PrintProgress(__LINE__); did = should = PR_FALSE; for (keys = 8; keys < 127; ++keys) @@ -260,6 +279,8 @@ static PRIntn PR_CALLBACK Tpd(PRIntn argc, char **argv) (void)PR_JoinThread(thread); + PrintProgress(__LINE__); + #if defined(WIN16) printf( "%s\n",((PR_TRUE == failed) ? "FAILED" : "PASSED")); diff --git a/pr/tests/udpsrv.c b/pr/tests/udpsrv.c index 4e9292d1..d45421d4 100644 --- a/pr/tests/udpsrv.c +++ b/pr/tests/udpsrv.c @@ -64,13 +64,6 @@ #include <string.h> #include <errno.h> -/* --- manifest constants --- */ -#ifdef XP_MAC -#define fprintf(a,b) printf(b) -#include "prlog.h" -#define printf PR_LogPrint -#endif - #ifdef XP_PC #define mode_t int #endif @@ -93,12 +86,13 @@ 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) printf(arg) +#define DPRINTF(arg) if (_debug_on) PR_fprintf(output, arg) + - /******************************************************************* ** ListNetAddr() -- Display the Net Address on stdout ** @@ -122,7 +116,7 @@ void ListNetAddr( char *msg, PRNetAddr *na ) DPRINTF( mbuf ); #endif } /* --- end ListNetAddr() --- */ - + /******************************************************************** ** UDP_Server() -- Test a UDP server application ** @@ -155,7 +149,9 @@ static void PR_CALLBACK UDP_Server( void *arg ) if ( svrSock == NULL ) { passed = PR_FALSE; - if (debug_mode) printf("udpsrv: UDP_Server(): PR_NewUDPSocket() returned NULL\n" ); + if (debug_mode) + PR_fprintf(output, + "udpsrv: UDP_Server(): PR_NewUDPSocket() returned NULL\n" ); return; } @@ -174,7 +170,7 @@ static void PR_CALLBACK UDP_Server( void *arg ) { if ( PR_GetError() == PR_ADDRESS_IN_USE_ERROR ) { - if (debug_mode) printf("udpsrv: UDP_Server(): \ + if (debug_mode) PR_fprintf(output, "udpsrv: UDP_Server(): \ PR_Bind(): reports: PR_ADDRESS_IN_USE_ERROR\n"); PR_Sleep( PR_MillisecondsToInterval( 2000 )); continue; @@ -182,7 +178,7 @@ static void PR_CALLBACK UDP_Server( void *arg ) else { passed = PR_FALSE; - if (debug_mode) printf( "udpsrv: UDP_Server(): \ + if (debug_mode) PR_fprintf(output, "udpsrv: UDP_Server(): \ PR_Bind(): failed: %ld with error: %ld\n", rv, PR_GetError() ); PR_Close( svrSock ); @@ -202,8 +198,10 @@ static void PR_CALLBACK UDP_Server( void *arg ) if ( rv == -1 ) { passed = PR_FALSE; - if (debug_mode) printf( "udpsrv: UDP_Server(): PR_RecvFrom(): failed with error: %ld\n", - PR_GetError() ); + if (debug_mode) + PR_fprintf(output, + "udpsrv: UDP_Server(): PR_RecvFrom(): failed with error: %ld\n", + PR_GetError() ); PR_Close( svrSock ); return; } @@ -223,8 +221,10 @@ static void PR_CALLBACK UDP_Server( void *arg ) if ( rv == -1 ) { passed = PR_FALSE; - if (debug_mode) printf( "udpsrv: UDP_Server(): PR_SendTo(): failed with error: %ld\n", - PR_GetError() ); + if (debug_mode) + PR_fprintf(output, + "udpsrv: UDP_Server(): PR_SendTo(): failed with error: %ld\n", + PR_GetError() ); PR_Close( svrSock ); return; } @@ -237,14 +237,16 @@ static void PR_CALLBACK UDP_Server( void *arg ) if ( rv != PR_SUCCESS ) { passed = PR_FALSE; - if (debug_mode) printf("udpsrv: UDP_Server(): PR_Close(): failed to close socket\n" ); + 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]; /******************************************************************** @@ -284,7 +286,9 @@ static void PR_CALLBACK UDP_Client( void *arg ) if ( cltSock == NULL ) { passed = PR_FALSE; - if (debug_mode) printf("udpsrv: UDP_Client(): PR_NewUDPSocket() returned NULL\n" ); + if (debug_mode) + PR_fprintf(output, + "udpsrv: UDP_Client(): PR_NewUDPSocket() returned NULL\n" ); return; } @@ -307,14 +311,18 @@ static void PR_CALLBACK UDP_Client( void *arg ) { if ( PR_GetError() == PR_ADDRESS_IN_USE_ERROR ) { - if (debug_mode) printf("udpsrv: UDP_Client(): PR_Bind(): reports: PR_ADDRESS_IN_USE_ERROR\n"); + 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) printf( "udpsrv: UDP_Client(): PR_Bind(): failed: %ld with error: %ld\n", + if (debug_mode) + PR_fprintf(output, + "udpsrv: UDP_Client(): PR_Bind(): failed: %ld with error: %ld\n", rv, PR_GetError() ); PR_Close( cltSock ); return; @@ -352,7 +360,7 @@ static void PR_CALLBACK UDP_Client( void *arg ) writeThisMany -= numBytes; { char mbuf[256]; - sprintf( mbuf, "udpsrv: UDP_Client(): write_this_many: %ld, numbytes: %ld\n", + sprintf( mbuf, "udpsrv: UDP_Client(): write_this_many: %d, numbytes: %d\n", writeThisMany, numBytes ); DPRINTF( mbuf ); } @@ -362,7 +370,9 @@ static void PR_CALLBACK UDP_Client( void *arg ) if ( rv == -1 ) { passed = PR_FALSE; - if (debug_mode) printf( "udpsrv: UDP_Client(): PR_SendTo(): failed with error: %ld\n", + if (debug_mode) + PR_fprintf(output, + "udpsrv: UDP_Client(): PR_SendTo(): failed with error: %ld\n", PR_GetError() ); PR_Close( cltSock ); return; @@ -376,7 +386,8 @@ static void PR_CALLBACK UDP_Client( void *arg ) if ( rv == -1 ) { passed = PR_FALSE; - if (debug_mode) printf( "udpsrv: UDP_Client(): PR_RecvFrom(): failed with error: %ld\n", + if (debug_mode) PR_fprintf(output, + "udpsrv: UDP_Client(): PR_RecvFrom(): failed with error: %ld\n", PR_GetError() ); PR_Close( cltSock ); return; @@ -393,12 +404,13 @@ static void PR_CALLBACK UDP_Client( void *arg ) if ( endOfInput && i == 0 && cltBufin[0] == 'E' ) continue; passed = PR_FALSE; - if (debug_mode) printf("udpsrv: UDP_Client(): return data mismatch\n" ); + if (debug_mode) PR_fprintf(output, + "udpsrv: UDP_Client(): return data mismatch\n" ); PR_Close( cltSock ); return; } } - if (debug_mode) printf("."); + if (debug_mode) PR_fprintf(output, "."); } /* --- Close the socket --- */ @@ -407,12 +419,13 @@ static void PR_CALLBACK UDP_Client( void *arg ) if ( rv != PR_SUCCESS ) { passed = PR_FALSE; - if (debug_mode) printf("udpsrv: UDP_Client(): PR_Close(): failed to close socket\n" ); + 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 ** @@ -461,6 +474,7 @@ int main(int argc, char **argv) PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); PR_STDIO_INIT(); + output = PR_STDERR; #ifdef XP_MAC SetupMacPrintfLog("udpsrv.log"); @@ -481,7 +495,7 @@ int main(int argc, char **argv) 0 ); if ( srv == NULL ) { - if (debug_mode) printf( "udpsrv: Cannot create server thread\n" ); + if (debug_mode) PR_fprintf(output, "udpsrv: Cannot create server thread\n" ); passed = PR_FALSE; } @@ -504,7 +518,7 @@ int main(int argc, char **argv) 0 ); if ( clt == NULL ) { - if (debug_mode) printf( "udpsrv: Cannot create server thread\n" ); + if (debug_mode) PR_fprintf(output, "udpsrv: Cannot create server thread\n" ); passed = PR_FALSE; } @@ -518,7 +532,7 @@ int main(int argc, char **argv) /* ** Evaluate test results */ - if (debug_mode) printf( "\n\nudpsrv: main(): cltBytesRead(%ld), \ + 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 ) diff --git a/pr/tests/version.c b/pr/tests/version.c new file mode 100644 index 00000000..c5c3013d --- /dev/null +++ b/pr/tests/version.c @@ -0,0 +1,101 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +#include "prio.h" +#include "prprf.h" +#include "prlink.h" +#include "prvrsion.h" + +#include "plerror.h" +#include "plgetopt.h" + +PRIntn main(PRIntn argc, char **argv) +{ + PRIntn rv = 1; + PLOptStatus os; + PRIntn verbosity = 0; + PRLibrary *runtime = NULL; + const char *library_name = NULL; + const PRVersionDescription *version_info; + 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) + PR_fprintf(err, "Usage: version [-d] {fully qualified library name}\n"); + else + { + runtime = PR_LoadLibrary(library_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); + rv = 0; + } + } + } + return rv; +} + +/* version.c */ |