summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorlarryh%netscape.com <devnull@localhost>1999-02-23 23:09:54 +0000
committerlarryh%netscape.com <devnull@localhost>1999-02-23 23:09:54 +0000
commit1b977761f99fac1224e911a305d0af1a53ed335c (patch)
tree15a23c4590d028dd4239b6b5a8201fdd11768287
parent593709bb4acda94b02c3aef0ee5bbf51e333fa3e (diff)
downloadnspr-hg-1b977761f99fac1224e911a305d0af1a53ed335c.tar.gz
add test case for plevent
-rw-r--r--lib/tests/Makefile20
-rw-r--r--lib/tests/event.c360
2 files changed, 375 insertions, 5 deletions
diff --git a/lib/tests/Makefile b/lib/tests/Makefile
index 61f88a58..3db362c0 100644
--- a/lib/tests/Makefile
+++ b/lib/tests/Makefile
@@ -27,6 +27,7 @@ endif
CSRCS = \
string.c \
+ event.c \
base64t.c
ifeq ($(OS_ARCH), WINNT)
@@ -46,15 +47,24 @@ INCLUDES = -I$(DIST)/include
LDOPTS = -L$(DIST)/lib
LIBPR = -lnspr$(MOD_VERSION)
LIBPLC = -lplc$(MOD_VERSION)
+LIBDS = -lplds$(MOD_VERSION)
ifeq ($(OS_ARCH), WINNT)
ifeq ($(OS_TARGET), WIN16)
LIBPR = $(DIST)/lib/nspr$(MOD_VERSION).lib
LIBPLC= $(DIST)/lib/plc$(MOD_VERSION).lib
+ LIBDS= $(DIST)/lib/plds$(MOD_VERSION).lib
else
-LDOPTS = -NOLOGO -DEBUG -DEBUGTYPE:CV -INCREMENTAL:NO
-LIBPR = $(DIST)/lib/libnspr$(MOD_VERSION).$(LIB_SUFFIX)
-LIBPLC= $(DIST)/lib/libplc$(MOD_VERSION).$(LIB_SUFFIX)
+ LDOPTS = -NOLOGO -DEBUG -DEBUGTYPE:CV -INCREMENTAL:NO
+ ifeq ($(OS_TARGET), WIN95)
+ LIBPR = $(DIST)/lib/nspr$(MOD_VERSION).$(LIB_SUFFIX)
+ LIBPLC= $(DIST)/lib/plc$(MOD_VERSION).$(LIB_SUFFIX)
+ LIBDS= $(DIST)/lib/plds$(MOD_VERSION).$(LIB_SUFFIX)
+ else
+ LIBPR = $(DIST)/lib/libnspr$(MOD_VERSION).$(LIB_SUFFIX)
+ LIBPLC= $(DIST)/lib/libplc$(MOD_VERSION).$(LIB_SUFFIX)
+ LIBDS= $(DIST)/lib/libpds$(MOD_VERSION).$(LIB_SUFFIX)
+ endif
endif
endif
@@ -175,10 +185,10 @@ ifeq ($(OS_TARGET),WIN16)
echo winsock.lib >>w16link
wlink @w16link.
else
- link $(LDOPTS) $< $(LIBPR) $(LIBPLC) wsock32.lib -out:$@
+ link $(LDOPTS) $< $(LIBPR) $(LIBPLC) $(LIBDS) wsock32.lib -out:$@
endif
else
- $(CC) $(XCFLAGS) $< $(LDOPTS) $(LIBPR) $(LIBPLC) $(EXTRA_LIBS) -o $@
+ $(CC) $(XCFLAGS) $< $(LDOPTS) $(LIBPR) $(LIBPLC) $(LIBDS) $(EXTRA_LIBS) -o $@
endif
endif
diff --git a/lib/tests/event.c b/lib/tests/event.c
new file mode 100644
index 00000000..4c8806df
--- /dev/null
+++ b/lib/tests/event.c
@@ -0,0 +1,360 @@
+/* -*- 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: event.c
+** Description: Test functions in plevent.c
+**
+** This test creates a number of threads. Each thread sends
+** an event to the next higher numbered (in creation order)
+** thread. On receipt of that event, that thread in turn
+** sends an event to the next thread until the event goes
+** around the circle of threads. The test self terminates
+** after a predetermined number of events have circled the
+** circle of threads.
+**
+**
+** Internal Design
+**
+** TState:
+** TState is the Event Handler State Strucuture. It
+** contains the state for an EventThread. There is one TState
+** structure per thread running in the EventThread()
+** function.
+**
+** TestEvents():
+** The TestEvent() function is the "real main()" function of
+** this test. The function creates 'numThreads' instances of
+** a thread running the EventThread() function. He then waits
+** for these threads to complete.
+**
+** EventThread():
+** The EventThread() function runs in the context of a thread
+** instance created by TestEvents(). The function processes
+** events from threads running the same function. An event is
+** created and sent around the ring
+**
+** EventHandler():
+** The EventHandler() function processes events received by
+** EventThread(). His job is to create and send a new event
+** to the next EventThread() thread in the ring of threads.
+**
+** EventDestructor():
+** The EventDestructor() function disposes of the event.
+** Required by the protocol for PLEvent.
+**
+**
+*/
+
+#include "nspr.h"
+#include "plgetopt.h"
+#include "plevent.h"
+
+/*
+** TState -- Event Handler State Structure
+**
+*/
+typedef struct TState
+{
+ PRIntn threadIndex; /* thread number. [0..n] */
+ PRIntn quitSwitch; /* when 0, running; when 1, order to quit */
+ PLEventQueue *eventQueue; /* event queue for this thread */
+} TState;
+
+/*
+** Thread Event structure
+*/
+typedef struct TEvent
+{
+ PLEvent plEvent;
+ PRIntn tIndex; /* Thread index of thread receiving event */
+ PRIntn quitSwitch; /* when 0, keep going; when 1 set TState[me].quitSwitch = 1 */
+} TEvent;
+
+static void PR_CALLBACK EventHandler( TEvent *ep );
+static void PR_CALLBACK EventDestructor( TEvent *ep );
+PR_EXTERN(PRIntn) TestEvents( void );
+
+/* --- Global data ---------------------------------------*/
+
+static PRIntn failed = 0; /* when 1, indicates test failed */
+static PRLogModuleInfo *lm; /* LogModule "test" */
+
+static PRIntn numThreads = 4; /* Number of threads in the ring */
+static PRIntn iterations = 7; /* Number of iterations per thread */
+
+static PRIntn iterationCount = 0; /* Counting times around the ring */
+
+static PRIntn activeThreads = 0; /* Number of active threads */
+static TState *tsa = NULL; /* array of all TStates */
+static PRMonitor *mon;
+static PRBool useMonitoredQueue = PR_FALSE;
+
+/*
+** SendEvent() -- Send an event to the next thread
+**
+*/
+static void SendEvent(
+ PRIntn threadIndex,
+ PRIntn quitSwitch
+)
+{
+ PLEventQueue *eq = (tsa+threadIndex)->eventQueue;
+ TEvent *event = PR_NEWZAP( TEvent );
+
+ PR_ASSERT( event != NULL );
+
+ PR_LOG( lm, PR_LOG_NOTICE, ("SendEvent: event: %p, threadIndex: %d quitSwitch: %d", event, threadIndex, quitSwitch ));
+ PL_ENTER_EVENT_QUEUE_MONITOR( eq );
+
+ PL_InitEvent( &event->plEvent, 0,
+ (PLHandleEventProc)EventHandler,
+ (PLDestroyEventProc)EventDestructor );
+ event->quitSwitch = quitSwitch;
+ event->tIndex = threadIndex;
+
+ PL_PostEvent( eq, &event->plEvent );
+ PL_EXIT_EVENT_QUEUE_MONITOR( eq );
+ return;
+} /* end SendEvent() */
+
+
+/*
+** EventHandler() -- Handle events posted from EventThread()
+**
+** if message says quit
+** Tell my thread to quit.
+** create an event, if I quit, pass it on.
+** PostEvent( TEvent.threadIndex+1)
+**
+*/
+static void PR_CALLBACK EventHandler( TEvent *ep )
+{
+ TState *ts = tsa+(ep->tIndex);
+ PRIntn ndx;
+
+ PR_LOG( lm, PR_LOG_NOTICE, ("EventHandler: %p, ti: %d", ep, ep->tIndex ));
+ if ( ep->quitSwitch == PR_TRUE )
+ ts->quitSwitch = PR_TRUE;
+
+ if ( ts->threadIndex == 0 )
+ {
+ if ( iterationCount++ >= iterations )
+ ep->quitSwitch = PR_TRUE;
+ }
+ /*
+ ** Calculate thread index of the next thread to get an event,
+ ** then send him the event.
+ */
+ ndx = ep->tIndex +1;
+ if ( ndx >= numThreads )
+ ndx = 0;
+
+ SendEvent( ndx, ep->quitSwitch );
+
+ return;
+} /* end EventHandler() */
+
+/*
+** EventDestructor() -- Free the event handled in EventHandler()
+**
+** free(the event)
+**
+*/
+static void PR_CALLBACK EventDestructor( TEvent *ep )
+{
+ PR_LOG( lm, PR_LOG_NOTICE, ("EventDestructor: event: %p", ep ));
+ PR_Free( ep );
+ return;
+} /* end EventDestructor() */
+
+/*
+** EventThread() -- Drive events around the ring of threads
+**
+** do
+** WaitforEvent()
+** HandleEvent()
+** PR_LOG( the event)
+** until told to quit
+**
+*/
+static void EventThread( void *arg )
+{
+ TEvent *ep;
+ TState *ts = (TState *)arg;
+
+
+ while ( ts->eventQueue == 0 )
+ PR_Sleep( PR_MillisecondsToInterval(100));
+
+ do {
+ ep = (TEvent *)PL_WaitForEvent( ts->eventQueue );
+ PL_HandleEvent( (PLEvent *)ep );
+ PR_LOG( lm, PR_LOG_NOTICE,("EventThread() Handled event: %d", ts->threadIndex ));
+ } while( ts->quitSwitch == 0 );
+
+ PR_EnterMonitor( mon );
+ activeThreads--;
+ PR_Notify( mon );
+ PR_ExitMonitor( mon );
+
+ PR_LOG( lm, PR_LOG_NOTICE,("EventThread() Exit: %d", ts->threadIndex ));
+
+ return;
+} /* end EventThread() */
+
+/*
+** TestEvents() --
+**
+** Create array of TEvents
+** CreateThreads of EventThreads
+** PostEvent() to the first EventThread
+** monitor for completion.
+** report results.
+**
+*/
+PR_IMPLEMENT( PRIntn ) TestEvents( void )
+{
+ PRIntn i;
+
+ lm = PR_NewLogModule( "test" );
+ PR_LOG( lm, PR_LOG_NOTICE,("TestEvent(): Starting" ));
+ mon = PR_NewMonitor();
+
+ /*
+ ** Allocate array of all TEvents
+ */
+ tsa = PR_Calloc( numThreads ,sizeof(TState));
+
+ /*
+ ** Initialize this event queue and create its thead
+ */
+ PR_ASSERT( tsa != NULL );
+ activeThreads = numThreads;
+ for ( i = 0 ; i < numThreads; i++ )
+ {
+ PRThread *me;
+ PLEventQueue *eq;
+
+ (tsa +i)->threadIndex = i;
+ (tsa +i)->quitSwitch = 0;
+ me = PR_CreateThread( PR_USER_THREAD,
+ EventThread,
+ (void *)(tsa +i),
+ PR_PRIORITY_NORMAL,
+ PR_LOCAL_THREAD,
+ PR_UNJOINABLE_THREAD,
+ 0 );
+ if ( me == NULL )
+ {
+ PR_LOG( lm, PR_LOG_ERROR, ("TestEvents: Can't create thread %d", i ));
+ exit(1);
+ }
+
+ if ( useMonitoredQueue == PR_TRUE )
+ eq = PL_CreateMonitoredEventQueue( "EventThread", me );
+ else
+ eq = PL_CreateNativeEventQueue( "EventThread", me );
+ PR_ASSERT( eq != NULL );
+
+ (tsa+i)->eventQueue = eq;
+ }
+
+
+ /*
+ ** Post and event to the first thread in the ring
+ ** to get things started.
+ */
+ SendEvent( 0, 0 );
+ /*
+ ** Wait for all threads to exit
+ */
+ PR_EnterMonitor( mon );
+ while ( activeThreads > 0 )
+ PR_Wait(mon, PR_INTERVAL_NO_TIMEOUT);
+ PR_ExitMonitor( mon );
+
+ /*
+ ** Release assets: event queue for each thread, the list of TStates.
+ */
+ for ( i = 0 ; i < numThreads; i++ )
+ {
+ PL_DestroyEventQueue( (tsa +i)->eventQueue );
+ }
+ PR_Free( tsa );
+
+ /*
+ ** All done! Log completion and return
+ */
+ PR_LOG( lm, PR_LOG_NOTICE,("TestEvent(): Ending" ));
+ return 0;
+} /* end TestEvents() */
+
+
+
+
+static void Help( void )
+{
+ printf( "Event: Help\n"
+ "syntax: event [-d][-h]\n"
+ "where: -h gives this message\n"
+ " -d sets debug mode (a no-op here)\n"
+ );
+} /* end Help() */
+
+PRIntn main(PRIntn argc, char **argv )
+{
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "dh");
+
+
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) continue;
+ switch (opt->option)
+ {
+ case 'm': /* use monitored event queue */
+ useMonitoredQueue = PR_TRUE;
+ break;
+ case 'd': /* debug mode (noop) */
+ break;
+ case 'h': /* needs guidance */
+ default:
+ Help();
+ return 2;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ TestEvents();
+ /*
+ ** Evaluate results and exit
+ */
+ if (failed)
+ {
+ printf("FAILED\n");
+ return(1);
+ }
+ else
+ {
+ printf("PASSED\n");
+ return(0);
+ }
+} /* end main() */
+
+/* end event.c */