home *** CD-ROM | disk | FTP | other *** search
- /*----------------------------------------------------------------------------
- This file is set up for a width of 130 columns, with tab stops
- every two spaces.
-
- HISTORY
-
- 10Oct93 DM New
- ----------------------------------------------------------------------------*/
-
- #import <mach/cthreads.h>
-
- #import "AppDelegate.h"
- #import "CircleView.h"
-
- static any_t increasingFunction(self)
- AppDelegate *self;
- {
- /*---------------------------------------------------------------
- Simple function that just generates an increasing series
- of numbers to display. this runs as an independent
- thread; we're forked and detached, then grab a connection to
- the main thread,and start sending messages to it.
-
- All four of these functions share some code. It should
- probably be factored out into a single method so the line
- count can be reduced.
- ---------------------------------------------------------------*/
- id proxy; // "proxy" object to the main server; essentially "self"
- int i; // generic int
-
- // Get a connection to the main server. This allows us to be detached,
- // yet talk to appkit and the DPS in a thread-safe way.
-
- proxy = [NXConnection connectToName:"fooServer"];
-
- // If we got nothing on the connect attempt, or if the object we got back
- // does not speak our "language", then punt.
-
- if((proxy == nil) || (![proxy conformsTo:@protocol(ServerInterface)]))
- {
- printf("Couldn't get connection to server object, or protocol is hosed\n");
- cthread_exit(0);
- }
-
- // Loop forever, generating an increasing sequence. We wrap after
- // some arbitrarily large number so we don't get overflow.
-
- while(YES)
- {
- i = 0;
- while(i < 128000)
- {
- [proxy showIncreasing:i]; // Tell the main thread to display this number
- i++;
-
- if(!self->isRunning)
- cthread_exit(0);
- cthread_yield(); // Be polite to the scheduler (not required)
- }
- }
-
- return 0;
- }
-
- static any_t fibFunction(self)
- AppDelegate *self;
- {
- /*------------------------------------------------------------------------
- Much like the above. We're running as a thread, and attach to the
- DO server and message that. We just generate a series of fib
- numbers for display.
- ------------------------------------------------------------------------*/
- id proxy; // Proxy to main server object
- int i, j, sum;
-
- // Get connection to main server
-
- proxy = [NXConnection connectToName:"fooServer"];
-
- // If we got nothing on the connect attempt, or if the object we got back
- // does not speak our "language", then punt.
-
- if((proxy == nil) || (![proxy conformsTo:@protocol(ServerInterface)]))
- {
- printf("Couldn't get connection to server object\n");
- cthread_exit(0);
- }
-
- // Generate new fib numbers forever. Roll over after some arbitrarily
- // large number to prevent overflow.
-
- while(YES)
- {
- i = 0; j = 1; sum = 0;
- [proxy showFib:i];
-
- while(i < 128000)
- {
- sum = i + j;
- [proxy showFib:sum];
- i = j;
- j = sum;
-
- if(!self->isRunning)
- cthread_exit(0);
-
- cthread_yield(); // Be polite to the scheduler (not required)
-
- }
- }
-
- return 0;
- }
-
- static any_t primeFunction(self)
- AppDelegate *self;
- {
- /*------------------------------------------------------------------------
- Much like the above. We're running as a thread, and attach to the
- DO server and message that. We just generate a series of prime
- numbers for display. I have no idea how the algo here works; just
- cut & pasted from something else.
- ------------------------------------------------------------------------*/
- id proxy; // Proxy to main server object
- int counter, possiblePrime = 5, testLimit;
- BOOL isPrime;
- List *primeList;
-
- // Get connection to main server
-
- proxy = [NXConnection connectToName:"fooServer"];
-
- // If we got nothing on the connect attempt, or if the object we got back
- // does not speak our "language", then punt.
-
- if((proxy == nil) || (![proxy conformsTo:@protocol(ServerInterface)]))
- {
- printf("Couldn't get connection to server object\n");
- cthread_exit(0);
- }
-
- // Sleaze alert: Lists are intended to hold ids, pointers to objects. If
- // we squint, and don't care a lot about nicities, we can also store ints
- // in them. The access is pretty slow, since it takes a function call
- // to find the contents of an address. But we could fix that if we liked
- // by just doing some pointer arithmetic into the List.
-
- primeList = [[List alloc] init];
- [primeList addObject:(id)2];
- [primeList addObject:(id)3];
-
- while (YES) // Repeat forever
- {
- isPrime = YES;
- testLimit = sqrt(possiblePrime);
- for (counter=1; isPrime && ((int)[primeList objectAt:counter]<=testLimit); counter++)
- if (possiblePrime % (int)[primeList objectAt:counter] == 0)
- isPrime = NO;
-
- if (isPrime)
- {
- [primeList addObject:(id)possiblePrime];
- [proxy showPrime:possiblePrime];
- }
- possiblePrime += 2;
-
- if(!self->isRunning)
- cthread_exit(0);
-
- cthread_yield(); // Be polite to the scheduler (not required)
-
- if(possiblePrime > 128000) // Begin again to prevent overflow
- {
- possiblePrime = 5;
- [primeList free];
- primeList = [[List alloc] init];
- [primeList addObject:(id)2];
- [primeList addObject:(id)3];
- }
- }
-
- return 0;
- }; // end of primeFunction
-
- static any_t circleFunction(self)
- AppDelegate *self;
- {
- /*------------------------------------------------------------------------
- Much like the above. We're running as a thread, and attach to the
- DO server and message that. We generate a series of points and
- radii, and send those to the main thread server. that draws
- the circles.
- ------------------------------------------------------------------------*/
- id proxy; // Proxy to main server object
- int maxHeight = 156, maxWidth = 255; // aprox. dimensions of the View
- NXPoint center;
- float radius;
- int x,y,r; // int versions of x, y, radius
-
- // Get connection to main server. Yeah, this common code ought to
- // be factored out into its own method. Sue me.
-
- proxy = [NXConnection connectToName:"fooServer"];
-
- // If we got nothing on the connect attempt, or if the object we got back
- // does not speak our "language", then punt.
-
- if((proxy == nil) || (![proxy conformsTo:@protocol(ServerInterface)]))
- {
- printf("Couldn't get connection to server object\n");
- cthread_exit(0);
- }
-
- // Generate a series of points and radii, and pass them off
- // to the main thread for drawing.
-
- srandom(1); // initialize rng
-
- while(YES) // loop forever
- {
- x = random(); y = random(); r = random();
-
- // Get them scaled back to about the size of the view.
-
- center.x = (float)(((double)x/(double)MAXINT) * (double)maxWidth);
- center.y = (float)(((double)y/(double)MAXINT) * (double)maxHeight);
- radius = (float)((((double)r/(double)MAXINT)*2.0) * (double)maxHeight);
-
- [proxy drawRandomCircleAt:center withRadius:radius];
-
- if(!self->isRunning)
- cthread_exit(0);
-
- cthread_yield(); // Be polite to the scheduler.
-
- }
-
- return 0;
- }
-
-
- @implementation AppDelegate
-
- // The main methods called by the threads, which output things to the screen.
- // These are the implementations of the protocol declaration.
-
- - showIncreasing // Show an increasing number in the window
- :(int)pNumber; // INPUT: the number to show
- {
- /*-------------------------------------------------------------------------
- Make an addition to the scrolling display of data in the ScrollView
- for the "increasing number" display.
- -------------------------------------------------------------------------*/
- Text *textObj;
- char theNumber[256];
-
- sprintf(theNumber, "%d\n", pNumber);
- textObj = [increasingDisp docView];
-
- [self addToText:textObj string:theNumber];
-
- return self;
- } // end of showIncreasing
-
- - showPrime // Show a prime number in the window
- :(int)pPrime; // INPUT: the prime to show
- {
- /*-------------------------------------------------------------------------
- Make an addition to the scrolling display of data in the ScrollView
- for the "increasing prime" display.
- -------------------------------------------------------------------------*/
-
- Text *textObj;
- char theNumber[256];
-
- sprintf(theNumber, "%d\n", pPrime);
- textObj = [primeDisp docView];
-
- [self addToText:textObj string:theNumber];
-
- return self;
- } // end of showPrime:
-
- - showFib // Show a fibonaci number in the window
- :(int)pFib; // INPUT: the fib to show
- {
- /*-------------------------------------------------------------------------
- Make an addition to the scrolling display of data in the ScrollView
- for the "increasing fibonacci" display.
- -------------------------------------------------------------------------*/
-
- Text *textObj;
- char theNumber[256];
-
- sprintf(theNumber, "%d\n", pFib);
- textObj = [fibDisp docView];
-
- [self addToText:textObj string:theNumber];
-
- return self;
- } // end of showFib:
-
- - drawRandomCircleAt // Draw a circle at the given point with the given radius
- :(NXPoint)pPoint // INPUT: where to draw it at (the center)
- withRadius:(float)pRadius; // INPUT: the radius
- {
- /*-------------------------------------------------------------------------------
- Add a circle to the view that displays the random circles. This also adds
- a circle to the display list kept in the CircleView, which is probably
- overkill. But we will be able to redraw it in its current state anywhere.
- -------------------------------------------------------------------------------*/
- [circleView addCircleAt:pPoint withRadius:pRadius];
- [circleView display];
-
- return self;
- }
-
- // App initialization delegate method
-
- - appDidInit:sender;
- {
- // Vend ourselves to the universe (and our threads, too.)
- // This is run from the appkit; the idea is to allow anyone
- // to call us, and we handle all talking to the appkit.
-
- [NXConnection setDefaultTimeout:200000]; // Timeout period, in milliseconds
-
- connection = [NXConnection registerRoot:self withName:"fooServer"];
- [connection runFromAppKit];
-
- return self;
- }
-
- - doThreads:sender; // Starts doing things--slamming numbers to the screen
- {
- /*---------------------------------------------------------------
- Do some stuff. Namely, start the threads that display
- things to the screen. We have functions that do nothing
- but generate output; they message us via distributed objects
- and tell us what to display, and we do it.
- ---------------------------------------------------------------*/
-
- // Clear out any existing cruft in the views.
-
- [circleView emptyCircles];
- [circleView display];
-
- [[increasingDisp docView] selectAll:self];
- [[increasingDisp docView] delete:self];
-
- [[fibDisp docView] selectAll:self];
- [[fibDisp docView] delete:self];
-
- [[primeDisp docView] selectAll:self];
- [[primeDisp docView] delete:self];
-
-
- // Break off all the threads for the stuff we want to do-- draw circles,
- // calculate primes, whatever.
-
- // "I woke up this morning with a bad hangover, and my cthread was
- // missing. This happens all the time. It's detachable."
- // -- Not King Missile
-
- isRunning = YES;
-
- cthread_detach(cthread_fork(increasingFunction, self));
- cthread_detach(cthread_fork(fibFunction, self));
- cthread_detach(cthread_fork(primeFunction, self));
- cthread_detach(cthread_fork(circleFunction, self));
-
- return self;
- }
-
- - stopThreads:sender; // Stops all the treads
- {
- /*-----------------------------------------------------------------------
- Stops all the threads, while leaving the display as is.
- -----------------------------------------------------------------------*/
-
- isRunning = NO;
-
- return self;
- }
-
-
- - addToText // Utility method--adds text at end of given text obj
- :(Text*)pTextObj // INPUT: text obj to add to
- string:(char*)pString; // INPUT: the text we're adding
- {
- /*------------------------------------------------------------------------------
- This would be better implemented as a category method to the Text object,
- but that would probably just confuse things for the rookies out there.
- We have very similar code in three of our functions, that just add
- a number to the end of a scrolling text display. This does that, given
- the text object passed in and the text to append.
-
- If we _did_ use a category method, everyone could use this method, which
- is pretty useful.
- ------------------------------------------------------------------------------*/
- int length; // How many chars are in the text object
-
- length = [pTextObj textLength]; // find out how long...
- [pTextObj setSel:length :length]; // get a null selection at the end...
- [pTextObj replaceSel:pString]; // and replace it with our new text
-
- [pTextObj scrollSelToVisible]; // make sure we can see it.
-
- return self;
- }
-
- @end
-