home *** CD-ROM | disk | FTP | other *** search
- /*
- * dispatch.c - routines concerned with allowing the running part of
- * the application be "event-driven," even though there are normally
- * no events to process.
- * Put another way, these routines make it easier for the routines
- * which take a long time to run to drop back and check for user
- * events, without each one having to be able to handle all the
- * possible events.
- *
- * The routines allow routines to pass argument lists to called
- * routines, and for the called routines to return values to their
- * callers, but such values must be copied to heap storage if they
- * need to be retained past the initial call or return.
- *
- * Dispatched routines are passed a handle to a frame_t which they
- * can resize to use for per-instance local storage. This handle
- * is locked before each call, except for the initial call to an
- * instance (since the routine is going to resize it immediately).
- * The handle is unlocked when the routine returns.
- *
- * The frames of routines which pushCall another routine remain
- * locked until the calling routine returns after being popCalled
- * back to.
- */
-
- #include "RevRdist.h"
- #include "dispatch.h"
- #include <TransSkelProto.h>
-
-
- static frameHdl CallStack = 0;
- static short Request = R_CONT;
-
- /*
- *=========================================================================
- * dispatch() - TransSkel background routine which takes care of
- * calling the real routines to get work done.
- * entry: idle() must have been pushCall()ed
- *=========================================================================
- */
- void
- dispatch ()
- {
- short result;
- Longint start;
-
- if (!CallStack)
- {
- /*
- * The routine stack is empty! We are in deep trouble.
- */
- Clue0 = (SP) "\pdispatch";
- Clue1 = (SP) "\pCallStack";
- Clue2 = (SP) "\pinternal error";
- panic (true, E_SYS, nil);
- SkelBackground (nil);
- SkelWhoa ();
- return;
- }
- if (Pause == S_PAUSED)
- return;
- for (start = TickCount (); start == TickCount (); )
- {
- HLock ((Handle)CallStack);
- result = (*(*CallStack)->proc) (CallStack, Request, nil);
- if (CallStack)
- HUnlock ((Handle)CallStack);
- switch (result)
- {
- case R_CONT:
- /*
- * Current procedure wishes to be recalled.
- */
- Request = result;
- break;
-
- case R_ERROR:
- /*
- * Procedure detected a system error.
- * ALERT the user and then start a BACKOUT or QUIT based on the
- * response.
- * The procedure is responsible for setting ClueID, Clue0, and
- * Clue1
- */
- Request = R_BACKOUT;
- panic (false, E_SYS, nil);
- if (Quit)
- Request = R_QUIT;
- break;
-
- case R_BACKOUT:
- case R_QUIT:
- if (result > Request)
- Request = result; /* possibly increase seriousness */
- break;
- }
- }
- }
-
- /*
- *=========================================================================
- * pushCall (p, ap) - push call to dispatched routine
- * entry: p = Routine to call
- * ap = Ptr to argument list
- * returns: result of R_INIT call to routine
- * else R_ERROR if cannot get memory
- *=========================================================================
- */
- Integer
- pushCall (p, ap)
- dispProcPtr p;
- Ptr * ap;
- {
- register framePtr f;
- frameHdl h;
- frameHdl oldstack;
- short result;
-
- if (Watch)
- SetCursor (*Watch);
- oldstack = CallStack;
- h = (frameHdl) NewHandle (sizeof (frame_t) );
- if (h == nil)
- {
- if ((ClueID = ResError()) == 0)
- ClueID = memFullErr;
- Clue0 = (SP) "\ppushCall";
- Clue1 = (SP) "\pNewHandle";
- return R_ERROR;
- }
- f = *h;
- /*
- * Link frame into stack and call routine
- */
- f->proc = p;
- f->state = 0;
- f->link = CallStack;
- CallStack = h;
- /*
- * At this point, the callee's frameHdl is not locked, but the
- * caller's probably still is from when it was dispatch()ed.
- */
- result = (*p) (h, (short) R_INIT, ap);
- if (result != R_CONT)
- {
- CallStack = oldstack;
- DisposHandle ((Handle) h);
- }
- else
- MoveHHi ((Handle) h); /* since it spends a lot of time locked */
- return result;
- }
-
-
- /*
- *=========================================================================
- * popCall (request, rp) - pop frame off dispatch stack and restart
- * nested routine
- * entry: request = request parameter for uncovered routine (R_CONT)
- * rp = return parameter for uncovered routine
- * returns: result of call to uncovered routine, but
- * WARNING: the dispatch frame for the caller of popCall is gone when popCall
- * returns, which means popCall should almost always be called like:
- * return (popCall (...));
- *=========================================================================
- */
- Integer
- popCall (request, rp)
- short request;
- Ptr * rp;
- {
- register frameHdl h;
- register frameHdl oldstack;
- short result;
-
- oldstack = CallStack;
- CallStack = h = (*oldstack)->link;
- HLock ((Handle)h);
- /*
- * Note that for the duration of this first call to the resumed
- * routine, the exiting routine's automatic variables and dispatch
- * frame are still available.
- */
- result = ((*(*h)->proc) (h, request, rp));
- /*
- * When popCall returns to the pop'er, the pop'er's stack frame is
- * gone and must not be referenced.
- */
- HUnlock ((Handle)oldstack);
- DisposHandle ((Handle)oldstack);
- return result;
- }
-
-
-
- /*
- *=========================================================================
- * resizeFrame (fh, n) - grow a basic frame up to a larger size
- * entry: fh = handle to frame
- * n = total size, in bytes, needed for local memory
- * returns: 0 on success, added space has been zeroed
- * <> is OSErr
- *=========================================================================
- */
- OSErr
- resizeFrame (fh, n)
- register frameHdl fh;
- register Size n;
- {
- register Size cur;
- register OSErr error;
- register Ptr p;
-
- if (n < sizeof (frame_t))
- return paramErr;
- SetHandleSize ((Handle) fh, n);
- if (error = MemError ())
- return error;
- for (p = *(Handle)fh + sizeof (frame_t), n -= sizeof (frame_t); n; n--)
- *p++ = 0;
- return 0;
- }