home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1998 / MacHack 1998.toast / Papers / C++ Exceptions / µShell / Core Utilities / AEThreads.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-01  |  3.7 KB  |  175 lines  |  [TEXT/CWIE]

  1. #ifndef __AETHREADS__
  2. #include "AEThreads.h"
  3. #endif
  4. #ifndef __EXCEPTIONS__
  5. #include "Exceptions.h"
  6. #endif
  7. #ifndef __ERRORS__
  8. #include <Errors.h>
  9. #endif
  10. #include <AppleEvents.h>
  11.  
  12. typedef struct AEThreadDesc  AEThreadDesc;
  13. typedef struct AEThreadParam AEThreadParam;
  14.  
  15. struct AEThreadDesc                        // Kept in the OS refcon
  16. {
  17.     AEEventHandlerProcPtr    handler;    // The real handler
  18.     long                    refcon;        // The real refcon
  19.     Size                    stackSize;    // Shack size for handling event
  20.     ThreadOptions            options;    // Thread options for event
  21.     ThreadID                holder;        // used as a semaphore
  22. };
  23.  
  24. struct AEThreadParam                    // Used in spawning
  25. {
  26.     const AppleEvent*    event;
  27.     AppleEvent*            reply;
  28.     AEThreadDesc*        desc;
  29.     ThreadID            thread;
  30.     OSErr                result;
  31. };
  32.  
  33.  
  34. pascal OSErr    SpawnAEThread(const AppleEvent *theAppleEvent, AppleEvent *reply, long handlerRefcon);
  35. pascal long        AEThread(AEThreadParam* parms);
  36.  
  37. AEEventHandlerUPP gSpawnAEThreadUPP = nil;
  38.  
  39. #pragma segment foobar
  40.  
  41. pascal OSErr AEInstallThreadedEventHandler(
  42.     AEEventClass            theAEEventClass,
  43.     AEEventID                theAEEventID,
  44.     AEEventHandlerProcPtr    proc,
  45.     long                    handlerRefcon,
  46.     ThreadOptions            options,
  47.     Size                    stacksize)
  48. {
  49.     AEThreadDesc* desc = (AEThreadDesc*) NewPtr(sizeof(AEThreadDesc));
  50.     OSErr          err  = MemError();
  51.     
  52.     if (gSpawnAEThreadUPP == nil)
  53.     {
  54.         gSpawnAEThreadUPP = NewAEEventHandlerProc(SpawnAEThread);
  55.     }
  56.     
  57.     if (err == noErr)
  58.     {
  59.         desc->handler    = proc;
  60.         desc->refcon    = handlerRefcon;
  61.         desc->stackSize    = stacksize;
  62.         desc->options    = options;
  63.         desc->holder    = kNoThreadID;
  64.  
  65.         err = AEInstallEventHandler(theAEEventClass, theAEEventID, gSpawnAEThreadUPP, (long) desc, false);
  66.     }
  67.     
  68.     return err;
  69. }
  70.  
  71.     static OSStatus call_event_handler(va_list arg)
  72.     {
  73.         VA_ARG(AppleEvent*,        event,    arg);
  74.         VA_ARG(AppleEvent*,     reply,    arg);
  75.         VA_ARG(AEThreadDesc*,    desc,    arg);
  76.         
  77.         FailOSErr((*desc->handler)(event, reply, desc->refcon));
  78.  
  79.         return noErr;
  80.     }
  81.  
  82. pascal long AEThread(AEThreadParam* parms)
  83. {
  84.     AppleEvent        event;            // Original parameters we care about
  85.     AppleEvent        reply;
  86.     AEThreadDesc*    desc;
  87.     OSErr            err;
  88.  
  89.     event = *parms->event;            // copy these into our own stack frame
  90.     reply = *parms->reply;
  91.     desc  =  parms->desc;
  92.     
  93.                                     // Let caller know we're ready
  94.  
  95.     if ((parms->result = AESuspendTheCurrentEvent(&event)) != noErr)
  96.     {
  97.         return nil;                    // Bail if there's a problem
  98.     }
  99.  
  100.     // At this point, we need to let our caller return
  101.  
  102.     while (desc->holder != kNoThreadID)
  103.     {
  104.         YieldToThread(desc->holder);
  105.     }
  106.  
  107.     // We are now on our own
  108.  
  109.     err = Exception::CatchAEErrors(
  110.             reply.descriptorType != typeNull ? &reply : nil,
  111.             call_event_handler, &event, &reply, desc);
  112.     
  113.     err = AEResumeTheCurrentEvent(&event, &reply, kAENoDispatch, 0);    // This had better work
  114.  
  115. #if qDebug
  116.     LogIfErr(err, "AEResumeTheCurrentEvent failed - very bad");
  117. #endif
  118.  
  119.     return err;
  120. }
  121.  
  122. #pragma segment Spawn
  123.  
  124. pascal OSErr SpawnAEThread(const AppleEvent *event, AppleEvent *reply, long handlerRefcon)
  125. {
  126.     AEThreadParam param;
  127.     
  128.     param.event  = event;
  129.     param.reply  = reply;
  130.     param.desc     = (AEThreadDesc*) handlerRefcon;
  131.     param.thread = kNoThreadID;
  132.  
  133.     if (!param.desc)
  134.     {
  135.         param.result = paramErr;
  136.     }
  137.     else
  138.     {
  139.         while (param.desc->holder != kNoThreadID)    // make sure no-one else is trying to start a handler
  140.         {
  141.             YieldToAnyThread();
  142.         }
  143.         
  144.         if ((param.result = GetCurrentThread(¶m.desc->holder)) == noErr)    // Grab the semaphore
  145.         {
  146.             param.result = NewThread(kCooperativeThread,
  147.                             (ThreadEntryProcPtr) &AEThread,
  148.                             ¶m,
  149.                             param.desc->stackSize,
  150.                             param.desc->options,
  151.                             nil,
  152.                             ¶m.thread);
  153.             
  154.             if (param.result == noErr)
  155.             {
  156.                 param.result = 1;
  157.             
  158.                 do
  159.                 {
  160.                     YieldToThread(param.thread);
  161.                 }
  162.                 while (param.result == 1);    // Wait for thread to pick up parameters
  163.             }
  164.         }
  165.         
  166.         param.desc->holder = kNoThreadID;    // release any claims we have
  167.     }
  168.     
  169.     return param.result;
  170. }
  171.  
  172.  
  173.  
  174.  
  175.