diff options
author | larryh%netscape.com <devnull@localhost> | 1999-02-23 23:09:54 +0000 |
---|---|---|
committer | larryh%netscape.com <devnull@localhost> | 1999-02-23 23:09:54 +0000 |
commit | 1b977761f99fac1224e911a305d0af1a53ed335c (patch) | |
tree | 15a23c4590d028dd4239b6b5a8201fdd11768287 | |
parent | 593709bb4acda94b02c3aef0ee5bbf51e333fa3e (diff) | |
download | nspr-hg-1b977761f99fac1224e911a305d0af1a53ed335c.tar.gz |
add test case for plevent
-rw-r--r-- | lib/tests/Makefile | 20 | ||||
-rw-r--r-- | lib/tests/event.c | 360 |
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 */ |