Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
ListMania.c
/* |
File: ListMania.c |
Contains: Sample for demonstrating use of OT list utilities. |
Written by: Quinn "The Eskimo!" |
Copyright: Copyright © 1997-1999 by Apple Computer, Inc., All Rights Reserved. |
You may incorporate this Apple sample source code into your program(s) without |
restriction. This Apple sample source code has been provided "AS IS" and the |
responsibility for its operation is yours. You are not permitted to redistribute |
this Apple sample source code as "Apple sample source code" after having made |
changes. If you're going to re-distribute the source, we require that you make |
it clear in the source that the code was descended from Apple sample source |
code, but that you've made changes. |
Change History (most recent first): |
2/18/2001 Chad Jones Updated for Codewarrior IDE 4.1 and Carbonized for OSX |
7/22/1999 Karl Groethe Updated for Metrowerks Codewarror Pro 2.1 |
*/ |
///////////////////////////////////////////////////////////////////// |
// Need to include to be carbonized |
///////////////////////////////////////////////////////////////////// |
// Need to include to be carbonized |
#if defined(__MWERKS__) |
# include <carbon.h> |
# include <OpenTransport.h> |
# include <OpenTptInternet.h> |
# include <OpenTptSerial.h> |
# include <SIOUX.h> |
#else |
# include <CoreServices/CoreServices.h> |
#endif |
# include <stdio.h> |
///////////////////////////////////////////////////////////////////// |
// OTDebugStr is not defined in any OT header files, but it is |
// exported by the libraries, so we define the prototype here. |
extern pascal void OTDebugStr(const char* str); |
///////////////////////////////////////////////////////////////////// |
// This MoreAssertQ is used in replacement for OTAssert under carbon because |
// OTAssert is not in carbon. |
static void MoreAssertQ(Boolean mustBeTrue) |
{ |
if ( ! mustBeTrue ) { |
DebugStr("\pMoreAssertQ: Assertion failure."); |
} |
} |
///////////////////////////////////////////////////////////////////// |
// Notes |
// ----- |
// This sample is designed to illustrate the use of the OT link-list |
// routines in a simple producer/consumer environment. The objects |
// being produced and consumed are widgets, as defined by the Widget |
// data type. There are two key routines: ProduceWidgets and |
// ConsumeWidgets. The first routine produces widgets (either by |
// reusing previously consumed (ie free) widgets, or by creating new |
// ones) and puts them on a 'pending' list. The second consumes the |
// widgets by grabbing them off the pending list. After consuming |
// the widget (in this sample, "consumption" means merely printing |
// to stdout), the routine returns the widget to a free list. |
// |
// This sample uses OTLIFO routines throughout. OTLIFO routines |
// are atomic with respect to interrupts, threads, and (most probably |
// even MP tasks), and are faster than the standard Mac OS equivalents |
// (ie Enqueue/Dequeue). |
// |
// In this sample, all the code is running at SystemTask time, however |
// all the list management in the critical portions of the code |
// (ie ProduceWidgets and ConsumeWidgets) is perfectly safe to run |
// at interrupt time. [ConsumeWidgets is not interrupt safe at the |
// moment because it uses "printf", but you can make it interrupt safe |
// if your definition of "consumption" is interrupt safe.] |
// |
// Another advantage of the OT list management routines is that they |
// support putting elements on multiple different lists simultaneously. |
// For example, all widgets are on the "list of all the widgets |
// in the system" and one of either the free list or the pending list. |
// OT's list management makes this very easy to do. |
///////////////////////////////////////////////////////////////////// |
// The Widget data structure holds all the information for a widget |
// object. This includes: |
// |
// o fSequenceNumber -- A unique, monotonically increasing, sequence |
// number for each widget that is ever created. |
// o fCreationTime -- The time at which the widget was created. |
// o fLastProducedTime -- The time at which the widget was last produced. |
// |
// The data structure also holds two link fields. The first, fNext, |
// is used to link together all the elements on either the pending |
// or free widget lists. The second link field is used to link all |
// of the widgets together in one long list, regardless of what their |
// status is. |
struct Widget { |
OTLink fNext; |
OTLink fAllWidgets; |
UInt32 fSequenceNumber; |
OTTimeStamp fCreationTime; |
OTTimeStamp fLastProducedTime; |
}; |
typedef struct Widget Widget, *WidgetPtr; |
// The following three lists are used to hold lists of widgets. |
// gAllWidgetList is the list of all the widgets in the system. |
// gPendingWidgetList is the list of all the widgets that have |
// been produced and are awaiting consumption. gFreeWidgetList |
// is the list of all the widgets that are available for reuse |
// by the producer. |
// |
// A widget is always on the the gAllWidgetList (through its |
// fAllWidgets link) and is either on the gPendingWidgetList |
// or the gFreeWidgetList (through its fNext link). |
static OTLIFO gAllWidgetList; |
static OTLIFO gPendingWidgetList; |
static OTLIFO gFreeWidgetList; |
// gLastWidgetSequenceNumber holds the sequence number of the |
// last widget that was produced. When we produce a new widget, |
// we add one to this number to get the sequence number for the |
// new widget. |
static UInt32 gLastWidgetSequenceNumber; |
///////////////////////////////////////////////////////////////////// |
static void InitWidgetLists(void) |
// Initialises all of the widget lists to empty. |
{ |
gAllWidgetList.fHead = nil; |
gPendingWidgetList.fHead = nil; |
gFreeWidgetList.fHead = nil; |
gLastWidgetSequenceNumber = 0; |
} |
static WidgetPtr CreateWidget(void) |
// This routine creates a new widget and returns it to the |
// caller. The new widget is always added to the gAllWidgetList |
// through its fAllWidgets link, but is available to be linked to |
// another list through its fNext link. |
{ |
WidgetPtr result; |
// Allocate the memory for the widget. |
result = OTAllocMemInContext(sizeof(Widget),nil); |
MoreAssertQ(result != nil); //called if could not creat widget. |
// Fill out the information fields of the widget. Note the |
// use of OTAtomicAdd32 to increment gLastWidgetSequenceNumber |
// atomically. This guarantees that the sequence number is |
// unique, even if this routine is re-entered. |
OTMemzero(result, sizeof(Widget)); |
result->fSequenceNumber = OTAtomicAdd32(1, (long *) &gLastWidgetSequenceNumber); |
OTGetTimeStamp(&result->fCreationTime); |
// Add the widget to the list of all the widgets in the system. |
OTLIFOEnqueue(&gAllWidgetList, (OTLink *) &result->fAllWidgets); |
return (result); |
} |
static void ProduceWidgets(UInt32 howMany) |
// This routine produces howMany widgets and adds them |
// to the gPendingWidgetList. |
{ |
UInt32 i; |
OTLink *freeLink; |
WidgetPtr thisWidget; |
// Produce each new element in turn. |
for (i = 0; i < howMany; i++) { |
// Grab a free element off the front of the gFreeWidgetList. |
// If that returns nil, there is no free element and we have |
// to create a new widget. Otherwise, use OTGetLinkObject |
// to derive thisWidget from freeLink. |
freeLink = OTLIFODequeue(&gFreeWidgetList); |
if ( freeLink != nil ) { |
thisWidget = OTGetLinkObject(freeLink, Widget, fNext); |
} else { |
thisWidget = CreateWidget(); |
} |
// At this point thisWidget points to a free widget that is |
// not on the gFreeWidgetList. We now produce the widget, which in |
// this sample merely involves setting fLastProducedTime. |
OTGetTimeStamp(&thisWidget->fLastProducedTime); |
// Now add the widget to the list of produced widgets. |
OTLIFOEnqueue(&gPendingWidgetList, (OTLink *) &thisWidget->fNext); |
} |
} |
static void PrintWidget(WidgetPtr thisWidget) |
// Prints a widget to stdout. |
{ |
printf(" %03ld, Created @ %08lx%08lx, Produced @ %08lx%08lx", |
thisWidget->fSequenceNumber, |
thisWidget->fCreationTime.hi, thisWidget->fCreationTime.lo, |
thisWidget->fLastProducedTime.hi, thisWidget->fLastProducedTime.lo |
); |
fflush(stdout); |
} |
static void ConsumeWidgets(void) |
// This routine consumes all of the widgets that have been produced. |
{ |
OTLink *listToConsume; |
WidgetPtr thisWidget; |
// First start by atomically stealing the list of pending |
// widgets. This removes all of the widgets on gPendingWidgetList |
// and returns them to us in listToConsume. Then, reverse |
// the list so that we consume them in the same order they |
// were produced. |
// |
// Note that these two API routines are defined to deal with |
// the empty list case correctly, so we don't have to |
// explicitly test it ourselves. |
listToConsume = OTLIFOStealList(&gPendingWidgetList); |
listToConsume = OTReverseList(listToConsume); |
while ( listToConsume != nil ) { |
// Given the link element, derive the actual widget object. |
thisWidget = OTGetLinkObject(listToConsume, Widget, fNext); |
// Now consume the widget. In this sample, consuming |
// a widget merely involves printing it to stdout. |
PrintWidget(thisWidget); |
printf("\n"); |
fflush(stdout); |
// Move along to the next list element... |
listToConsume = listToConsume->fNext; |
// ... and enqueue the most recently consumed widget on |
// the list of free widgets. Note that the order of these |
// two operations is important, because thisWidget->fNext |
// is the same memory location as listToConsume->fNext, so |
// we can't change thisWidget->fNext (by enqueuing it) |
// until we have extracted the linkage information from it. |
OTLIFOEnqueue(&gFreeWidgetList, (OTLink *) &thisWidget->fNext); |
} |
} |
static void DumpWidgetList(OTLIFO *list) |
// Dump a widget list that is linked using the fNext field. |
// This is appropriate for the pending and free lists of widgets. |
{ |
OTLink *link; |
WidgetPtr thisWidget; |
link = list->fHead; |
while ( link != nil ) { |
thisWidget = OTGetLinkObject(link, Widget, fNext); |
PrintWidget(thisWidget); |
printf("\n"); |
fflush(stdout); |
link = link->fNext; |
} |
} |
static void DumpWidgetAllLists(void) |
// Dump each af the three global lists. |
{ |
OTLink *link; |
WidgetPtr thisWidget; |
printf("gPendingWidgetList\n"); |
DumpWidgetList(&gPendingWidgetList); |
printf("gFreeWidgetList\n"); |
DumpWidgetList(&gFreeWidgetList); |
printf("gAllWidgetList\n"); |
fflush(stdout); |
link = gAllWidgetList.fHead; |
while ( link != nil ) { |
thisWidget = OTGetLinkObject(link, Widget, fAllWidgets); |
PrintWidget(thisWidget); |
printf("\n"); |
link = link->fNext; |
} |
fflush(stdout); |
} |
///////////////////////////////////////////////////////////////////// |
int main(void) |
// A simple command line shell for testing the various |
// routines defined above. |
{ |
OSStatus err; |
Boolean quitNow; |
char commandString[256]; |
#if defined(__MWERKS__) |
SIOUXSettings.autocloseonquit = FALSE; // don't close the SIOUX window on program termination |
SIOUXSettings.asktosaveonclose = FALSE; // don't offer to save on a close |
#endif |
err = InitOpenTransportInContext(kInitOTForApplicationMask, nil); |
if (err == noErr) { |
InitWidgetLists(); |
printf("Enter a command:\n"); |
printf("p) Produce 3 widgets\n"); |
printf("P) Produce 5 widgets\n"); |
printf("c) Consume all pending widgets\n"); |
printf("d) Dump all widget lists\n"); |
printf("q) Quit\n"); |
printf("\n"); |
fflush(stdout); |
quitNow = false; |
do { |
printf("Enter a command:\n"); |
fflush(stdout); |
if (fgets(commandString,sizeof(commandString),stdin) == nil) |
{ |
commandString[0] = 0; |
} |
switch( commandString[0] ) { |
case 'q': |
case 'Q': |
quitNow = true; |
break; |
case 'c': |
case 'C': |
ConsumeWidgets(); |
break; |
case 'p': |
ProduceWidgets(3); |
break; |
case 'P': |
ProduceWidgets(5); |
break; |
case 'd': |
case 'D': |
DumpWidgetAllLists(); |
break; |
default: |
printf("Don't understand Ò%sÓ.",commandString); |
fflush(stdout); |
break; |
} |
} while ( ! quitNow ); |
CloseOpenTransportInContext(nil); |
} |
if (err == noErr) { |
printf("Success.\n"); |
} else { |
printf("Failed with error %ld.\n", err); |
} |
fflush(stdout); |
return(0); |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-14