home *** CD-ROM | disk | FTP | other *** search
- static char rcsid[] = "$Id: TestCounter.m,v 1.1 1997/04/02 18:28:43 croehrig Exp $";
- /*
- * Counter: simple counter object that runs in its own thread.
- */
- #import <libc.h>
- #import <math.h>
- #import <appkit/Button.h>
- #import <appkit/Slider.h>
- #import "Counter.h"
- #import "ThreadedApp.h"
- #import "tprintf.h"
-
- #define INITIAL_INTERVAL 100 // in milliseconds
-
- @interface Counter(CounterPrivate)
- - (int)incCount;
- - (void)counter:sender;
- @end
-
- @implementation Counter : Object
-
- // number of counters created
- static int counters;
-
- // global variable shared among all Counter instances
- static volatile int *countp;
-
- // lock to synchronize access to countp
- static CJRConditionLock *inclock;
-
- #define STOPPED 0
- #define RUNNING 1
-
- #define myrandom() (random()/(double)MAXINT)
- + initialize
- {
- if( self == [Counter class] ){
- srandom(0);
- counters = 1;
- inclock = [[CJRConditionLock alloc] initWithCondition:0];
- tprintf_init();
- }
- return self;
- }
-
-
- - init
- {
- NXScreen *screen;
- NXRect frame;
-
-
- [super init];
- interval = INITIAL_INTERVAL;
- running = NO;
- mynum = counters++;
-
- lastcount = -1;
- count = 0;
- if( [NXApp loadNibSection:"Counter.nib" owner:self] ){
- // set window title...
- title = (char *) malloc( 20*sizeof(char) ); // should be enough...
- sprintf( title, "Counter %d\n", mynum );
- [window setTitle:title];
-
- // move to random location
- [window getFrame:&frame andScreen:&screen];
- frame.size.width = screen->screenBounds.size.width
- - frame.size.width;
- frame.size.height = screen->screenBounds.size.height
- - frame.size.height;
- frame.origin = screen->screenBounds.origin;
- frame.origin.x += myrandom()*frame.size.width;
- frame.origin.y += myrandom()*frame.size.height;
- [window moveTo:frame.origin.x:frame.origin.y];
- [window makeKeyAndOrderFront:self];
-
- // set values
- [slider setIntValue:interval];
- [intervalField setIntValue:interval];
- [countField setIntValue:count];
-
- runlock = [[CJRConditionLock alloc] initWithCondition:STOPPED];
- // go!
- [self start:self];
- }
- return self;
- }
-
- - free
- {
- if( running )
- [self stop:self];
-
- [runlock free];
- if(title){
- free(title);
- }
- return [super free];
- }
-
-
- - windowWillClose:sender
- {
- [self stop:self];
- [NXApp delayedFree:self];
-
- return self;
- }
-
-
- // "private" methods
-
- - dispCount:(int)i
- {
- if( i != lastcount+1 ){
- tprintf("Counter %d: lost %d message(s)\n", mynum, i-lastcount-1);
- }
- [countField setIntValue:i];
- lastcount = i;
- return self;
- }
-
-
- - (int)incCount
- // a pretty dumb way to increment a counter, but it sure tests
- // the callback and lock mechanism...
- {
- [inclock lockWhenCondition:0];
- count++;
- countp = &count;
- [inclock unlockWithCondition:mynum];
-
- return count;
- }
-
-
- - (void)counter:sender
- {
- int i;
-
- [runlock lockWhenCondition:RUNNING];
- i = count;
- while( running ){
- // update countField under main thread
- [NXApp callbackTarget:self perform:@selector(dispCount:) with:(id)i];
-
- // increment the counter...
- [NXApp safeCallbackTarget:self perform:@selector(incCount)];
- [inclock lockWhenCondition:mynum];
- i = *countp;
- [inclock unlockWithCondition:0];
- if( i != count ){
- tprintf("Counter %d: count mismatch! ret=%d; count=%d\n",
- mynum, i, count );
- }
-
- if( interval > 0 )
- [NXApp sleepCurrentThread:interval];
- }
-
- [runlock unlockWithCondition:STOPPED];
- }
-
-
- // Actions...
-
- - start:sender
- {
- if( !running ){
- [runlock lock];
- [NXApp detachNewThreadSelector:@selector(counter:) toTarget:self
- withObject:self];
- running = YES;
- [runlock unlockWithCondition:RUNNING];
- }
- return self;
- }
-
-
- - stop:sender
- {
- if( running ){
- running = NO;
- // wait for thread to finish
- [runlock lockWhenCondition:STOPPED];
- [runlock unlock];
- }
-
- return self;
- }
-
- - startOrStop:sender
- {
- if( [sender state] == 0 ){
- [self start:sender];
- } else {
- [self stop:sender];
- }
- return self;
- }
-
-
- - reset:sender
- {
- count = 0;
- return self;
- }
-
-
- - setInterval:sender
- {
- int i, max;
-
- i = [sender intValue];
- max = (int) [slider maxValue];
- if( i < 0 ){
- i = 0;
- } else if( i > max ){
- i = max;
- }
- [slider setIntValue:i];
- [intervalField setIntValue:i];
-
- interval = i;
-
- return self;
- }
-
- @end
-