home *** CD-ROM | disk | FTP | other *** search
Text File | 1998-06-02 | 25.2 KB | 734 lines | [TEXT/CWIE] |
- /*
- File: Futures.c
-
- Contains: Futures package
-
- This code goes to pains to NOT use the exception handler, and therefore also
- avoids using AppleEventUtilities.cp, so that it will not be dependant on the
- need to switch out gExceptionStack on every thread context switch, and therefore
- should be able to run in conjunction with custom scheduler and custom thread
- swap routines without need for modification.
-
- The futures package will spawn new threads in two places: first, at InitFutures
- time, a new thread may be spawned to call IdleFutures Periodicly. Second,
- the predispatch handler, if installed, will fork a new thread every time an
- AppleEvent is dispatched.
- */
-
-
- #include "Futures.h"
- #include "Semaphores.h"
- #include "TimeUtils.h"
-
- #ifndef __APPLEEVENTS__
- #include <AppleEvents.h>
- #endif
-
- //
- // Keywords for special handlers not documented
- // in Inside Macintosh
- //
- #define keyAEBlock 'blck'
- #define keyAEUnblock 'unbk'
-
- //
- // Message ID of the event sent by AEResetTimer
- //
- #define kAEWaitLonger 'wait'
-
- //
- // Random, arbitrarily choosen keyword
- // for a parameter that probably doesn't exist.
- //
- #define keyNonexistantParameter 'nonx'
-
- //
- // Structure used just to pass parameters to the "RedispatchEvent" thread
- //
- struct AsyncPredispatchParameters
- {
- AppleEvent fAppleEvent;
- AppleEvent fReply;
- AEEventHandlerUPP fEventHandler;
- long fHandlerRefCon;
- };
-
- typedef struct AsyncPredispatchParameters AsyncPredispatchParameters;
-
- #if GENERATINGCFM
-
- //
- // The block and unblock special handlers are not
- // documented, so they do not have ProcInfo descriptions
- // for their callback in the Universal headers. Both
- // the block and the unblock routine take a single parameter:
- // the AppleEvent that is being blocked on / unblocked.
- //
- enum
- {
- uppAEBlockUnblockProcInfo = kPascalStackBased
- | RESULT_SIZE(SIZE_CODE(sizeof(OSErr)))
- | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(AEDesc*)))
- };
-
- #endif
-
- //
- // Private constants:
- //
- #define kCreateSemaphoreIfNotFound true
- #define kDontCreateSemaphoreIfNotFound false
-
-
- //
- // Private functions:
- //
- static OSErr NewFuturesThread(ThreadEntryProcPtr threadEntry, void *threadParam, long handlerRefCon, ThreadID *threadMade);
- static TSemaphore* GetFutureSemaphore(AppleEvent* reply, Boolean createIfNotFound);
- static pascal OSErr AEBlock(AppleEvent* reply);
- static pascal OSErr AEUnblock(AppleEvent* reply);
- static pascal OSErr WaitLongerEvent(AppleEvent* ae, AppleEvent* reply, long refCon);
- static pascal OSErr AsyncPreDispatchHandler(AppleEvent* ae, AppleEvent* reply, long refCon);
- static void RedispatchEvent(void* threadParam);
- static OSErr GetAEMHandlerUPPFromOneTable(AEEventClass theAEEventClass, AEEventID theAEEventID, AEEventHandlerUPP *handler, long *handlerRefcon, Boolean isSysHandler);
- static OSErr GetAppleEventHandlerUPP(AppleEvent* ae, AEEventHandlerUPP *handler, long *handlerRefCon);
- static long PrivateFuturesThread(long threadParam);
- static void FillInDefaultTimeoutValues(long& timeout);
-
-
- #if GENERATINGCFM
-
- static RoutineDescriptor gAEBlockRD = BUILD_ROUTINE_DESCRIPTOR(uppAEBlockUnblockProcInfo, AEBlock);
- static RoutineDescriptor gAEUnblockRD = BUILD_ROUTINE_DESCRIPTOR(uppAEBlockUnblockProcInfo, AEUnblock);
- static RoutineDescriptor gWaitLongerEventRD = BUILD_ROUTINE_DESCRIPTOR(uppAEEventHandlerProcInfo, WaitLongerEvent);
- static RoutineDescriptor gAsyncPreDispatchRD = BUILD_ROUTINE_DESCRIPTOR(uppAEEventHandlerProcInfo, AsyncPreDispatchHandler);
-
- #endif // GENERATINGCFM
-
- //
- // Globals:
- //
- ThreadCreateProcPtr gThreadCreateProc = nil;
-
- //----------------------------------------------------------------------------------------
- // InitFutures:
- //
- // Install the block and unblock routines.
- //
- // If spawnHousekeepingThread is true, then a thread will be forked to idle the
- // Futures package. If you pass false for this boolean, your code must call
- // IdleFutures Periodicly.
- //
- // If installAsyncPreDispatchHandler is true, then the futures package will
- // install a predispatch handler that automatically forks a new thread every
- // time AEProcessAppleEvents is called, so that all of your application's
- // event handlers may be processed asynchronously.
- //----------------------------------------------------------------------------------------
- OSErr InitFutures(ThreadCreateProcPtr threadCreateProc, long initFuturesFlags)
- {
- ThreadID futuresHousekeepingThreadID = kNoThreadID;
- OSErr err = noErr;
-
- TSemaphore::InitializeGlobals();
-
- gThreadCreateProc = threadCreateProc;
-
- #if GENERATINGCFM
- if(err == noErr)
- err = AEInstallSpecialHandler(keyAEBlock, &gAEBlockRD, false);
- if(err == noErr)
- err = AEInstallSpecialHandler(keyAEUnblock, &gAEUnblockRD, false);
- if(err == noErr)
- err = AEInstallEventHandler(kCoreEventClass, kAEWaitLonger, &gWaitLongerEventRD, 0, false);
- #else
- if(err == noErr)
- err = AEInstallSpecialHandler(keyAEBlock, (UniversalProcPtr) AEBlock, false);
- if(err == noErr)
- err = AEInstallSpecialHandler(keyAEUnblock, (UniversalProcPtr) AEUnblock, false);
- if(err == noErr)
- err = AEInstallEventHandler(kCoreEventClass, kAEWaitLonger, (AEEventHandlerProcPtr) &WaitLongerEvent, 0, false);
- #endif
-
- //
- // Create the housekeeping thread.
- // We could probably use a very small stack for this thread.
- //
- if((err == noErr) && (initFuturesFlags & kSpawnHousekeepingThread))
- err = NewFuturesThread((ThreadEntryProcPtr)PrivateFuturesThread, 0, 0, &futuresHousekeepingThreadID);
-
- //
- // If an async pre-dispatch handler was requested, then install it.
- //
- if((err == noErr) && (initFuturesFlags & kInstallAsyncPreDispatchHandler))
- {
- #if GENERATINGCFM
- err = AEInstallSpecialHandler(keyPreDispatch, &gAsyncPreDispatchRD, false);
- #else
- err = AEInstallSpecialHandler(keyPreDispatch, (UniversalProcPtr)AsyncPreDispatchHandler, false);
- #endif
- }
-
- return err;
- } // InitFutures
-
- //----------------------------------------------------------------------------------------
- // BlockUntilReal:
- //
- // Block the current thread until the specified message becomes real. This function
- // works by accessing a nonexistant parameter of the reply; the AppleEvent manager will
- // block any access to the reply, since (obviously) it doesn't know what the parameters
- // of the reply will be until the reply actually arrives.
- //----------------------------------------------------------------------------------------
- void BlockUntilReal(AppleEvent* reply)
- {
- long nonExistentParameterStorage;
- long actualSize;
- DescType typeCode;
-
- //
- // Ask for the non existent parameter; this will cause the AppleEvent
- // manager to block on the event
- //
- AEGetParamPtr(reply, keyNonexistantParameter, typeLongInteger, &typeCode, (Ptr) &nonExistentParameterStorage, sizeof(long), &actualSize);
- } // BlockUntilReal
-
- //----------------------------------------------------------------------------------------
- // ReplyArrived
- //
- // Return 'true' if the reply can be accessed without blocking, or false if it
- // is still a future
- //----------------------------------------------------------------------------------------
- Boolean ReplyArrived(AppleEvent* ae)
- {
- UniversalProcPtr oldBlockRoutine = nil;
- long nonExistentParameterStorage;
- long actualSize;
- DescType typeCode;
- Boolean arrived = false;
-
- OSErr err = AEGetSpecialHandler(keyAEBlock, &oldBlockRoutine, false);
- if(err == noErr)
- err = AERemoveSpecialHandler(keyAEBlock, oldBlockRoutine, false);
-
- //
- // Ask for the non existent parameter; this will cause the AppleEvent
- // manager to return errAEReplyNotArrived if the reply is still a future;
- // some other error (such as paramter not found) will be returned if
- // the reply has arrived
- //
- if(err == noErr)
- {
- arrived = (AEGetParamPtr(ae, keyNonexistantParameter, typeLongInteger, &typeCode, (Ptr) &nonExistentParameterStorage, sizeof(long), &actualSize) != errAEReplyNotArrived);
- err = AEInstallSpecialHandler(keyAEBlock, oldBlockRoutine, false);
- }
-
- return arrived;
- } // ReplyArrived
-
- //----------------------------------------------------------------------------------------
- // SetReplyTimeoutValue
- //
- // Specify how long the reply should wait in between reset-timer notifications, and
- // how much total time the reply should wait before giving up on a server that keeps
- // reseting the timer but never delivers results.
- //----------------------------------------------------------------------------------------
- void SetReplyTimeoutValue(AppleEvent* reply, long timeoutValue /* = kNeverTimeoutSemaphore */, long maxWaitTime /* = kNeverTimeoutSemaphore */)
- {
- FillInDefaultTimeoutValues(timeoutValue);
- FillInDefaultTimeoutValues(maxWaitTime);
-
- TSemaphore* semaphore = GetFutureSemaphore(reply, kCreateSemaphoreIfNotFound);
- if(semaphore)
- {
- // DebugStr("\pSet reply timout value");
- semaphore->SetSemaphoreTimoutValue(timeoutValue);
- semaphore->SetSemaphoreMaxWaitTime(maxWaitTime);
- }
- else
- DebugStr("\pCouldn't make semaphore to set timeout value");
- }
-
- //----------------------------------------------------------------------------------------
- // IdleFutures
- //
- // Usually, this routine doesn't need to be called, as it is done automatically by
- // the private futures thread, installed by InitFutures.
- //----------------------------------------------------------------------------------------
- void IdleFutures()
- {
- TSemaphore::Idle();
- }
-
- //----------------------------------------------------------------------------------------
- // AskForFuture
- //----------------------------------------------------------------------------------------
- OSErr AskForFuture(AppleEvent* ae, AppleEvent* reply, long timeoutValue /* = kAEDefaultTimeout */, long maxWaitTime /* = 0x7FFFFFFF */, AESendMode sendMode, AESendPriority sendPriority /* = kAENormalPriority */)
- {
- OSErr err = noErr;
-
- FillInDefaultTimeoutValues(timeoutValue);
-
- long resetFrequency = timeoutValue / 2;
-
- err = AEPutAttributePtr(ae, keyAEResetTimerFrequencyAttr, typeLongInteger, (Ptr)&resetFrequency, sizeof(long));
- if(err == noErr)
- err = AESend(ae, reply, sendMode | kAEWaitReply, sendPriority, 0, nil, nil);
- if(err == errAETimeout)
- err = noErr;
- if(err == noErr)
- SetReplyTimeoutValue(reply, timeoutValue, maxWaitTime);
-
- return err;
- }
-
- //----------------------------------------------------------------------------------------
- // GetResetTimerFrequency
- //
- // Determines how frequently a server application is advised to call AEResetTimer
- //----------------------------------------------------------------------------------------
- long GetResetTimerFrequency(AppleEvent* ae)
- {
- DescType typeCode;
- long actualSize;
- long resetTimerFrequency = 0;
-
- //
- // First look at keyAEResetTimerFrequencyAttr; if that attribute
- // does not exist, try half of keyAETimeoutAttr
- //
- if(AEGetAttributePtr(ae, keyAEResetTimerFrequencyAttr, typeLongInteger, &typeCode, (Ptr)&resetTimerFrequency, sizeof(long), &actualSize) != noErr)
- {
- if(AEGetAttributePtr(ae, keyTimeoutAttr, typeLongInteger, &typeCode, (Ptr)&resetTimerFrequency, sizeof(long), &actualSize) == noErr)
- resetTimerFrequency /= 2;
- else
- resetTimerFrequency = 0;
- }
-
- //
- // If we couldn't find a frequency, use the default
- //
- if(resetTimerFrequency == 0)
- resetTimerFrequency = kDefaultResetTimerFrequency;
-
- return resetTimerFrequency;
- }
-
- //----------------------------------------------------------------------------------------
- // ResetTimerIfNecessary
- //
- // Calls AEResetTimer if enough time has elapsed.
- //----------------------------------------------------------------------------------------
- OSErr ResetTimerIfNecessary(AppleEvent* reply, unsigned long* lastReset, long resetFrequency)
- {
- OSErr err = noErr;
- unsigned long currentTime = TickCount();
-
- //
- // Set up 'lastReset' the first time in
- //
- if(*lastReset == 0)
- *lastReset = currentTime;
-
- //
- // We won't be so extreme as to enforce a minimum reset
- // frequency, but we don't allow zero!
- //
- if(resetFrequency == 0)
- resetFrequency = kDefaultResetTimerFrequency;
-
- //
- // TimeExpired is in Semaphores.c; it determines if 'currentTime' has
- // gone beyond 'lastReset + resetFrequency', handling the unavoidable
- // tickcount wraparound that happens every 771 days.
- //
- if(TimeExpired(currentTime, *lastReset, *lastReset + resetFrequency))
- {
- // DebugStr("\pAbout to call AEResetTimer");
-
- *lastReset = currentTime;
- err = AEResetTimer(reply);
- }
-
- return err;
- }
-
- //----------------------------------------------------------------------------------------
- // NewFuturesThread
- //
- // This routine calls either 'NewThread' or the application-defined thread creation
- // procedure.
- //----------------------------------------------------------------------------------------
- static OSErr NewFuturesThread(ThreadEntryProcPtr threadEntry, void *threadParam, long handlerRefCon, ThreadID *threadMade)
- {
- OSErr err = noErr;
- Size stackSize = 0;
- ThreadOptions options = kCreateIfNeeded | kFPUNotNeeded;
-
- if(gThreadCreateProc != nil)
- err = (*gThreadCreateProc)(threadEntry, threadParam, handlerRefCon, threadMade);
- else
- err = NewThread(kCooperativeThread, threadEntry, threadParam, stackSize, options, nil, threadMade);
-
- return err;
- }
-
- //----------------------------------------------------------------------------------------
- // GetFutureSemaphore:
- //
- // This function returns the semaphore that this event is blocked on, or
- // nil if the event is not blocked
- //----------------------------------------------------------------------------------------
- static TSemaphore* GetFutureSemaphore(AppleEvent* reply, Boolean createIfNotFound)
- {
- TSemaphore* semaphore = nil;
- long semaphoreID = 0;
-
- //
- // Use the reply's return ID as the semaphore ID.
- //
- // We need to set the semaphore ID when the current thread
- // blocks on the future; once the reply arrives, we need to
- // pull the semaphore ID out of the reply. Therefore, we'd
- // better use an attribute that exists before and after the
- // reply arrives.
- //
- // Another important point: we can access the return ID attribute
- // without causing the block routine to be called--very important,
- // as we need to get the semaphore out of the message from
- // within the block routine!
- //
- DescType typeCode;
- long actualSize;
- if(AEGetAttributePtr(reply, keyReturnIDAttr, typeLongInteger, &typeCode, (Ptr)&semaphoreID, sizeof(long), &actualSize) == noErr)
- semaphore = TSemaphore::FindSemaphore(semaphoreID, createIfNotFound, 0);
- else
- DebugStr("\pCould not get return attr from reply");
-
- return semaphore;
- } // GetFutureSemaphore
-
- //----------------------------------------------------------------------------------------
- // AEBlock:
- //
- // This routine is installed as the special handler "block", which is called by the
- // AppleEvent manager whenever a routine that tries to extract information from a
- // future (an AppleEvent reply that has not yet arrived) is called.
- //----------------------------------------------------------------------------------------
- static pascal OSErr AEBlock(AppleEvent* reply)
- {
- TSemaphore* semaphore = nil;
- OSErr err = noErr;
-
- // DebugStr("\pAEBlock");
-
- //
- // Look up the semaphore attached to this message. This will
- // only rarely exist; the only time that it would exist would
- // be if multiple threads tried to pull information out of
- // the same future. In that case, the first thread would create
- // the semaphore, and the second thread would then get and
- // block on the same semaphore.
- //
- semaphore = GetFutureSemaphore(reply, kCreateSemaphoreIfNotFound);
-
- //
- // If we have a semaphore, then block on it.
- // 'errAETimeout' is one error that may
- // come out of 'Grab' (if we go to sleep
- // for a while, then give up). Note, however,
- // that the AppleEvent manager will always
- // return errAEReplyNotArrived if AEBlock
- // returns anything other than noErr.
- //
- if(semaphore != nil)
- {
- err = semaphore->Grab();
- semaphore->Release();
- }
- //
- // If we can't block, then return
- // errAEReplyNotArrived right away
- //
- else
- err = errAEReplyNotArrived;
-
- return err;
- } // AEBlock
-
- //----------------------------------------------------------------------------------------
- // AEUnblock:
- //
- // This function is called by the AppleEvent manager when a future that was blocked
- // on becomes a real event (i.e., when the reply actually arrives). When that happens,
- // we need to unblock all threads that are blocked on this future.
- //----------------------------------------------------------------------------------------
- static pascal OSErr AEUnblock(AppleEvent* reply)
- {
- TSemaphore* semaphore = nil;
- OSErr err = noErr;
-
- // DebugStr("\pAEUnblock");
-
- //
- // The AppleEvent manager may call the unblock routine
- // even if the block routine was never called, so there
- // may or may not be a semaphore attached to the message
- //
- semaphore = GetFutureSemaphore(reply, kDontCreateSemaphoreIfNotFound);
- if(semaphore != nil)
- {
- // DebugStr("\pAbout to release all threads");
- semaphore->Dispose();
- }
-
- return err;
- } // AEUnblock
-
- //----------------------------------------------------------------------------------------
- // WaitLongerEvent:
- //
- // Notify the reply that some activity was reported from the server.
- //----------------------------------------------------------------------------------------
- static pascal OSErr WaitLongerEvent(AppleEvent* ae, AppleEvent* /*reply*/, long /*refCon*/)
- {
- // DebugStr("\pWaitLongerEvent");
-
- //
- // Note that the return ID of the wait longer event
- // is the same as the return ID of the reply whose
- // semaphore we want to look up; the reply to the
- // wait longer event is not used for anything, because
- // the AppleEvent manager sends the wait longer event
- // "no reply".
- //
- TSemaphore* semaphore = GetFutureSemaphore(ae, kDontCreateSemaphoreIfNotFound);
- if(semaphore)
- {
- // DebugStr("\pFound semaphore to reset timer on");
- semaphore->ResetTimeoutTimer();
- }
- //else
- // DebugStr("\pGot wait longer event but did not find semaphore");
-
- return noErr;
- } // WaitLongerEvent
-
- //----------------------------------------------------------------------------------------
- // AsyncPreDispatchHandler:
- //----------------------------------------------------------------------------------------
- static pascal OSErr AsyncPreDispatchHandler(AppleEvent* ae, AppleEvent* reply, long /*refCon*/)
- {
- //
- // By default, assume that we are not going to handle this event;
- // If we return 'errAEEventNotHandled', the AppleEvent manager will
- // continue dispatching this event. We let the AEM handle events
- // without any handler, and events that would be handled by a system
- // event handler (which we know will never yield, and therefore
- // do not need to run in a thread).
- //
- OSErr err = errAEEventNotHandled;
- AsyncPredispatchParameters** dispatchParams = nil;
- AEEventHandlerUPP handler = nil;
- long handlerRefCon = 0;
-
- //
- // Look up the event handler and refCon in the AppleEvent tables;
- // if we can't find a handler, then we'll let the AppleEvent
- // manager do the dispatching.
- //
- if(GetAppleEventHandlerUPP(ae, &handler, &handlerRefCon) == noErr)
- {
- dispatchParams = (AsyncPredispatchParameters**)NewHandle(sizeof(AsyncPredispatchParameters));
- if(dispatchParams != nil)
- {
- //
- // Save the AppleEvent message and reply. We don't need to
- // save the event handler's refCon, because the AppleEvent
- // manager will look it up again when the event is redispatched.
- //
- (*dispatchParams)->fAppleEvent = *ae;
- (*dispatchParams)->fReply = *reply;
- (*dispatchParams)->fEventHandler = handler;
- (*dispatchParams)->fHandlerRefCon = handlerRefCon;
-
- //
- // Make a new thread
- //
- ThreadID newThreadID;
- if(NewFuturesThread((ThreadEntryProcPtr)RedispatchEvent, (void*)dispatchParams, handlerRefCon, &newThreadID) == noErr)
- {
- dispatchParams = nil;
-
- //
- // Always suspend the current event. AEResumeTheCurrentEvent
- // will be called to redispatch the event after it has been
- // forked into a thread.
- //
- AESuspendTheCurrentEvent(ae);
-
- //
- // Set 'err' to 'noErr', indicating that we have handled
- // the event.
- //
- err = noErr;
- }
- }
- }
-
- //
- // If the 'dispatchParams' were created, but we couldn't
- // fork a new thread, then dispose of them here. Otherwise,
- // they will be disposed when the event is redispatched.
- //
- if(dispatchParams != nil)
- DisposeHandle((Handle)dispatchParams);
-
- return err;
- } // AsyncPreDispatchHandler
-
-
- //----------------------------------------------------------------------------------------
- // RedispatchEvent
- //----------------------------------------------------------------------------------------
- static void RedispatchEvent(void* threadParam)
- {
- OSErr err = noErr;
-
- //
- // Extract the AppleEvent, Reply, event handler UPP and
- // message refCon from the thread parameter, which we
- // know is a handle to our predispatch parameters.
- //
- AsyncPredispatchParameters** dispatchParams = (AsyncPredispatchParameters**)threadParam;
- AppleEvent ae = (*dispatchParams)->fAppleEvent;
- AppleEvent reply = (*dispatchParams)->fReply;
- AEEventHandlerUPP handler = (*dispatchParams)->fEventHandler;
- long handlerRefCon = (*dispatchParams)->fHandlerRefCon;
- DisposeHandle((Handle)dispatchParams);
-
- //
- // Call the event handler directly
- //
- err = CallAEEventHandlerProc(handler, &ae, &reply, handlerRefCon);
-
- //
- // If the event handler returned an error, we need to do
- // exactly what the AppleEvent manager would do in the
- // same situation: jam the error into keyErrorNumber
- // iff there isn't a keyErrorNumber in the reply already.
- // This is necessary because there is no way to pass
- // the error code into AEResumeTheCurrentEvent
- //
- if(err != noErr)
- {
- DescType actualType = typeNull;
- long actualSize = 0;
- long errorResult = 0;
-
- if(AEGetParamPtr(&reply, keyErrorNumber, typeLongInteger, &actualType, &errorResult, sizeof(long), &actualSize) != noErr)
- {
- errorResult = err;
- AEPutParamPtr(&reply, keyErrorNumber, typeLongInteger, &errorResult, sizeof(long));
- }
- }
-
- //
- // When our handler returns, call AEResumeTheCurrentEvent
- // without dispatching, so that the AppleEvent manager
- // will send the reply.
- //
- AEResumeTheCurrentEvent(&ae, &reply, (AEEventHandlerUPP)kAENoDispatch, 0);
- }
-
- //----------------------------------------------------------------------------------------
- // GetAEMHandlerUPPFromOneTable
- //----------------------------------------------------------------------------------------
- static OSErr GetAEMHandlerUPPFromOneTable(AEEventClass theAEEventClass, AEEventID theAEEventID, AEEventHandlerUPP *handler, long *handlerRefCon, Boolean isSysHandler)
- {
- OSErr err = AEGetEventHandler(theAEEventClass, theAEEventID, handler, handlerRefCon, isSysHandler);
- if(err != noErr)
- err = AEGetEventHandler(typeWildCard, theAEEventID, handler, handlerRefCon, isSysHandler);
- if(err != noErr)
- err = AEGetEventHandler(theAEEventClass, typeWildCard, handler, handlerRefCon, isSysHandler);
- if(err != noErr)
- err = AEGetEventHandler(typeWildCard, typeWildCard, handler, handlerRefCon, isSysHandler);
-
- return err;
- }
-
- //----------------------------------------------------------------------------------------
- // GetAppleEventHandlerUPP
- //----------------------------------------------------------------------------------------
- static OSErr GetAppleEventHandlerUPP(AppleEvent* ae, AEEventHandlerUPP *handler, long *handlerRefCon)
- {
- AEEventClass theAEEventClass;
- AEEventID theAEEventID;
- DescType actualType = typeNull;
- long actualSize = 0;
-
- //
- // Look up the event class and the event ID of the AppleEvent
- // so that we can look it up in the event handler dispatch table
- //
- OSErr err = AEGetAttributePtr(ae, keyEventClassAttr, typeType, &actualType, &theAEEventClass, sizeof(AEEventClass), &actualSize);
- if(err == noErr)
- err = AEGetAttributePtr(ae, keyEventIDAttr, typeType, &actualType, &theAEEventID, sizeof(AEEventID), &actualSize);
-
- if(err == noErr)
- {
- err = GetAEMHandlerUPPFromOneTable(theAEEventClass, theAEEventID, handler, handlerRefCon, false);
-
- #if 0
- //
- // We don't need to search the system event handler table, because we can
- // let AEResumeTheCurrentEvent(kAEUseStandardDispatch) do that. We know
- // that system event handlers don't yield, so this is safe.
- //
- if(err != noErr)
- err = GetAEMHandlerUPPFromOneTable(theAEEventClass, theAEEventID, handler, handlerRefCon, true);
- #endif
- }
-
- return err;
- }
-
-
- //----------------------------------------------------------------------------------------
- // PrivateFuturesThread
- //
- // This thread does periodic tasks for the Futures package; currently, it only checks
- // to see if there are any futures that have timed out. Note that TSemaphore::Idle
- // calls TickCount(), and performs no action most of the time.
- //
- // Unfortunately, there's no way for this thread to tell the thread manager that it
- // doesn't need to be swapped in for a number of ticks; it has to keep getting scheduled,
- // do nothing, get scheduled again, and so on for most of its life.
- //----------------------------------------------------------------------------------------
- static long PrivateFuturesThread(long /* threadParam */)
- {
- for(;;)
- {
- IdleFutures();
- YieldToAnyThread();
- }
-
- return 0;
- }
-
- //----------------------------------------------------------------------------------------
- // FillInDefaultTimeoutValues
- //
- // This function converts from negative default constants to the actual positive
- // number that the constant is translated into.
- //----------------------------------------------------------------------------------------
- static void FillInDefaultTimeoutValues(long& timeout)
- {
- //
- // ••• What should the default timeout be?
- //
- if(timeout == kAEDefaultTimeout)
- timeout = 1200;
- else if(timeout < 0)
- timeout = 0x7FFFFFFF;
- }
-