home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C++ / Applications / Nuntius 1.2 / src / Nuntius / UThreadLongJmp.cp < prev    next >
Encoding:
Text File  |  1994-03-16  |  4.9 KB  |  189 lines  |  [TEXT/MPS ]

  1. // Copyright © 1993 Peter Speck (speck@dat.ruc.dk).  All rights reserved.
  2. // UThreadLongJmp.cp
  3.  
  4. #include "UThreadLongJmp.h"
  5. #include "UFatalError.h"
  6.  
  7. #include <RsrcGlobals.h>
  8.  
  9. #include <GestaltEqu.h>
  10. #include <SysEqu.h>
  11.  
  12. #pragma segment MyThread
  13.  
  14. #define qDebugSchedule qDebug & 0
  15.  
  16. const long kInitialStackSize = 24 * 1024;
  17. long gThreadLongJmpID = 99;
  18.  
  19. //==============================================================================
  20.  
  21. TThreadLongJmp::TThreadLongJmp()
  22. {
  23. }
  24.  
  25. pascal void TThreadLongJmp::Initialize()
  26. {
  27.     inherited::Initialize();
  28.     BlockSet(Ptr(&fLongJmpBuf), sizeof(fLongJmpBuf), 0);
  29.     fLongJmpBuf.fStack = nil;
  30. }
  31.  
  32. void TThreadLongJmp::IThreadLongJmp(Boolean isMainThread, const char *debugDoingWhat)
  33. {
  34.     inherited::IThread(isMainThread, debugDoingWhat);
  35.     FailInfo fi;
  36.     if (fi.Try())
  37.     {
  38.         fLongJmpBuf.fID = ++gThreadLongJmpID;
  39.         if (isMainThread == false)
  40.         {
  41.             *( (void**)StkLowPt ) = 0;
  42.             fLongJmpBuf.fStack = NewPermPtr(kInitialStackSize);
  43.             Ptr stackEndP = fLongJmpBuf.fStack + kInitialStackSize;
  44.             fLongJmpBuf.fStackTop = stackEndP - 1;
  45.             fLongJmpBuf.SP = (long*)stackEndP - 64;
  46.             fLongJmpBuf.fHeapEnd = (long*)fLongJmpBuf.fStack;
  47.             fLongJmpBuf.fApplLimit = (long*)fLongJmpBuf.fStack;
  48.             fLongJmpBuf.fHiHeapMark = (long*)fLongJmpBuf.fStack;
  49.         }
  50.         fi.Success();
  51.     }
  52.     else // fail
  53.     {
  54.         FreeIfObject(this);
  55.         fi.ReSignal();
  56.     }
  57. }
  58.  
  59. pascal void TThreadLongJmp::Free()
  60. {
  61.     DisposeIfPtr(fLongJmpBuf.fStack); fLongJmpBuf.fStack = nil;
  62.     inherited::Free();
  63. }
  64.  
  65. void TThreadLongJmp::Die()
  66. {
  67. #if qDebugSchedule
  68.     fprintf(stderr, "ThreadDie, id = %ld, %s\n", fLongJmpBuf.fID, fDebugDoingWhat);
  69. #endif
  70.     Ptr stack = fLongJmpBuf.fStack; // we're going to shoot ourself!
  71.     fLongJmpBuf.fStack = nil;
  72.     inherited::Die();
  73.     TThreadLongJmp *nextThread = (TThreadLongJmp*)MySchedule();
  74.     nextThread->SwapIn(stack);
  75.     PanicExitToShell("In TThreadLongJmp::Die, got past end of world");
  76. }
  77.  
  78. //-----------------------------------------------------------------------------
  79. void TThreadLongJmp::SwapIn(Ptr ptrToDispose)
  80. {
  81.     MyLongJmp68000(fLongJmpBuf, ptrToDispose);
  82. }
  83.  
  84. //==============================================================================
  85.  
  86. void TThreadLongJmp::ExecCmd(TCommand *cmd)
  87. {
  88.     FailNonObject(this);
  89.     RestoreState();
  90.     if (qDebugSchedule)
  91.         fprintf(stderr, "Switch++,  id = %ld, cmd = $%lx, %s\n", fLongJmpBuf.fID, cmd, fDebugDoingWhat);
  92.     ThreadExecuteCommand(cmd);
  93.     PanicExitToShell("In TThreadLongJmp::ExecCmd, returned from ThreadExecuteCommand");
  94. }
  95.  
  96. void TThreadLongJmp::StartThread(TCommand *cmd)
  97. {
  98.     gAllThreads->InsertLast(this);
  99.     fIsStarted = true;
  100. #if qDebugSchedule
  101.     fprintf(stderr, "Starts LongJmpThread id = %ld (%s)\n", fLongJmpBuf.fID, fDebugDoingWhat);
  102. #endif
  103.     if (fIsMainThread)
  104.         return;
  105.     fLongJmpBuf.PC = (const void*)&TThreadLongJmp::ExecCmd;
  106.     fLongJmpBuf.A6 = 0;
  107.     long *sp = fLongJmpBuf.SP;
  108.     // when called, SP points to return address (non-existing)
  109.     sp[0] = 0xF1F1F1F1;
  110.     sp[1] = long(this);
  111.     sp[2] = long(cmd);
  112. }
  113.  
  114. void TThreadLongJmp::SwapThread()
  115. {
  116.     TThreadLongJmp *nextThread = (TThreadLongJmp*)MySchedule();
  117.     VOLATILE(nextThread);
  118.     if (nextThread == this)
  119.     {
  120. #if qDebug
  121.         fprintf(stderr, "MySchedule to current thread, id = %ld, %s\n", fLongJmpBuf.fID, fDebugDoingWhat);
  122. #endif
  123.         return;
  124.     }
  125.     SaveState();
  126.     if (qDebugSchedule)
  127.         fprintf(stderr, "SwitchOut, id = %ld, %s\n", fLongJmpBuf.fID, fDebugDoingWhat);
  128.     if (MySetJmp68000(fLongJmpBuf) == 0) // zero after set, nonzero after return
  129.         nextThread->SwapIn(nil);
  130.     if (qDebugSchedule)
  131.         fprintf(stderr, "SwitchIn,  id = %ld, %s\n", fLongJmpBuf.fID, fDebugDoingWhat);
  132.     RestoreState();
  133. }
  134.  
  135. void TThreadLongJmp::DumpDebugDescription()
  136. {
  137.     inherited::DumpDebugDescription();
  138.     long stackFree = long(fLongJmpBuf.SP) - long(fLongJmpBuf.fStack);
  139.     fprintf(stderr, "       id = %ld, stack-free = %ld\n", fLongJmpBuf.fID, stackFree);
  140. }
  141. //===============================================================================
  142. TThread *ExecuteInNewThreadLongJmp(TCommand *command, const char *debugDoingWhat)
  143. {
  144. #if qDebugSchedule
  145.     fprintf(stderr, "ExecuteInNewThreadLongJmp, cmd = $%lx, doing: %s\n", command, debugDoingWhat);
  146. #endif
  147.     TThreadLongJmp *thread = nil;
  148.     VOLATILE(thread);
  149.     //
  150.     FailInfo fi;
  151.     if (fi.Try())
  152.     {
  153.         TThreadLongJmp *ta = new TThreadLongJmp();
  154.         ta->IThreadLongJmp(false, debugDoingWhat);
  155.         thread = ta;
  156.         //
  157.         FailSpaceIsLow();
  158.         thread->StartThread(command);
  159.         //
  160.         fi.Success();
  161.         return thread;
  162.     }
  163.     else // fail
  164.     {
  165.         FreeIfObject(command); command = nil;
  166.         FreeIfObject(thread); thread = nil;
  167.         fi.ReSignal();
  168.     }
  169. }
  170. //===========================================================================
  171. Boolean HasThreadLongJmp()
  172. {
  173.     long resp;
  174.     // not 100% compatible with MacPlus, just like Apples Thread Manager:
  175.     if (Gestalt(gestaltMachineType, resp) != noErr)
  176.         return false;
  177.     if (resp == gestaltMacPlus)
  178.         return false;
  179.     return true;
  180. }
  181.  
  182. TThread *CreateMainThreadLongJmp()
  183. {
  184.     TThreadLongJmp *thread = new TThreadLongJmp();
  185.     thread->IThreadLongJmp(true, "main thread");
  186.     thread->StartThread(nil);
  187.     return thread;
  188. }
  189.