home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1995 February: Tool Chest / Dev.CD Feb 95 / Dev.CD Feb 95.toast / New System Software Extensions / ASLM SDK v1.1.2 / ASLM Examples / TestTools / Sources / TestTimeScheduler.cp < prev    next >
Encoding:
Text File  |  1994-11-21  |  21.6 KB  |  986 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        TestTimeScheduler.cp
  3.  
  4.     Contains:    Tester for the TTimeScheduler class
  5.  
  6.     Copyright:    © 1991-1993 by Apple Computer, Inc., all rights reserved.
  7.  
  8. */
  9.  
  10. #ifndef __TESTTIMESCHEDULER__
  11. #include "TestTimeScheduler.h"
  12. #endif
  13.  
  14. const size_t    kNumOps    = 5;
  15.  
  16. #define kCloseness    1
  17.  
  18. /**********************************************************************
  19. ** TTimeOperation methods
  20. ***********************************************************************/
  21.  
  22. TTimeOperation::TTimeOperation(TTimeScheduler* theSched, int which)
  23. {
  24.     fSched    = theSched;
  25.     fTest    = 0;
  26.     fWatch    = NULL;
  27.     fWhich    = which;
  28.     fFired    = false;
  29. }
  30.  
  31. TTimeOperation::~TTimeOperation()
  32. {
  33.     if (fTest != 9)
  34.         DebugStr("\pIn TTimeOperation destructor when we shouldn't be!");
  35.     delete fWatch;
  36.     fTest = 10;
  37. }
  38.  
  39. void TTimeOperation::Process()
  40. {
  41.     switch (fTest)
  42.     {
  43.         case 0:
  44.             if (fFired)
  45.                 DebugStr("\pBummer - timer fired a second time");
  46.             fFired = true;
  47.             break;
  48.             
  49.         case 1:
  50.             if (fFired)
  51.                 DebugStr("\pBummer - timer fired a second time");
  52.             fFired = true;
  53.             if (!fSched->Remove(this))
  54.                 DebugStr("\pBummer - remove didn't work");
  55.             else
  56.             {
  57.                 if (!fSched->DeleteInProcessOperation(this))
  58.                     DebugStr("\pScheduler won't process DeleteInProcessOperation call");
  59.                 else
  60.                 {
  61.                     if (!WasRemovedInProcess())
  62.                         DebugStr("\pWasRemovedInProcess returned false");
  63.                     ClearRemovedInProcess();
  64.                 }
  65.             }
  66.             break;
  67.             
  68.         case 2:
  69.             if (!fSched->Remove(this))
  70.                 DebugStr("\pBummer - remove didn't work");
  71.             else
  72.             {
  73.                 if (!fSched->RerunInProcessOperation(this))
  74.                     DebugStr("\pScheduler won't process RerunInProcessOperation call");
  75.                 else
  76.                 {
  77.                     if (!WasRemovedInProcess())
  78.                         DebugStr("\pWasRemovedInProcess returned false");
  79.                     fTest = 3;
  80.                 }
  81.             }
  82.             break;
  83.  
  84.         case 3:
  85.             fFired = true;
  86.             if (!WasRemovedInProcess())
  87.                 DebugStr("\pWasRemovedInProcess returned false");
  88.             ClearRemovedInProcess();
  89.             break;
  90.  
  91.         case 4:
  92.             fFired = true;
  93.             SetTime((kNumOps + 1)*500 - fWhich*500);
  94.             fTest = 5;
  95.             break;
  96.  
  97.         case 5:
  98.             if (!fFired)
  99.                 DebugStr("\pBummer - haven't already fired");
  100.             fTest = 20;
  101.             break;
  102.             
  103.         case 6:
  104.             fFired = true;
  105.             if (!fSched->Remove(this))
  106.                 DebugStr("\pBummer - remove didn't work");
  107.             SetTime((kNumOps + 1)*500 - fWhich*500);
  108.             fTest = 7;
  109.             fSched->Schedule(this);
  110.             break;
  111.  
  112.         case 7:
  113.             DebugStr("\pBummer - shouldn't get here");
  114.             fTest = 21;
  115.             break;
  116.             
  117.         case 8:
  118.             fFired = true;
  119.             SetDeleteWhenDone();
  120.             fTest = 9;
  121.             break;
  122.             
  123.         case 30:
  124.             unsigned long temp = fWatch->ElapsedMilliseconds();
  125.             fFired = true;
  126.             fDifference = (int)(temp - fWhen);
  127.             break;
  128.                             
  129.     }
  130. }
  131.  
  132. /**********************************************************************
  133. ** Class TTimeMatcher
  134. ***********************************************************************/
  135.  
  136. class TTimeMatcher : public TMatchObject
  137. {
  138.     public:
  139.                         TTimeMatcher(int toMatch);
  140.         virtual            ~TTimeMatcher();
  141.         
  142.         virtual Boolean    IsEqual(const void*) const;
  143.         
  144.         int    fMatch;
  145. };
  146.  
  147. TTimeMatcher::TTimeMatcher(int toMatch)
  148. {
  149.     fMatch = toMatch;
  150. }
  151.  
  152. TTimeMatcher::~TTimeMatcher()
  153. {}
  154.  
  155. Boolean TTimeMatcher::IsEqual(const void* obj) const
  156. {
  157.     return ((const TTimeOperation*)obj)->fWhich == fMatch;
  158. }
  159.  
  160. /**********************************************************************
  161. ** PUBLIC Constructor/Destructor 
  162. ***********************************************************************/
  163.  
  164. Constructor(TimeScheduler)
  165. Destructor(TimeScheduler)
  166.  
  167. /**********************************************************************
  168. ** PUBLIC InitTest
  169. ***********************************************************************/
  170.  
  171. void TTestTimeScheduler :: InitTest(Boolean, Boolean, int argc, char** argv)
  172. {    
  173.     size_t            idx;
  174.     TStandardPool*    pool = GetPool();
  175.  
  176.     if (pool == NULL)
  177.     {
  178.         Printf("### ERROR: There is no global pool\n");
  179.         return;
  180.     }
  181.         
  182.     if ((fTest = new (pool) TTimeScheduler) == NULL)
  183.         Printf("### ERROR: Couldn't create a new TTimeScheduler\n");
  184.         
  185.     fTest->SetAutoReschedule(true);
  186.     fNumOperations    = kNumOps;
  187.     fResolution        = 50;
  188.     fIterations        = 100;
  189.     fStress            = false;
  190.     fMaxSchedule    = 2500;
  191.     fMinSchedule    = 1;
  192.     idx = 0;
  193.     while (argc)
  194.     {
  195.         char*    str;
  196.         
  197.         str = argv[idx];
  198.         if (*str != '-')
  199.             break;
  200.         argc -= 1;
  201.         idx += 1;
  202.         switch (str[1])
  203.         {
  204.             case 'n':
  205.             case 'N':
  206.                 fNumOperations = NumToString(argv[idx++]);
  207.                 argc -= 1;
  208.                 break;
  209.             
  210.             case 'm':
  211.             case 'M':
  212.                 if (argc >= 2)
  213.                 {    
  214.                     fMinSchedule = NumToString(argv[idx++]);
  215.                     fMaxSchedule = NumToString(argv[idx++]);
  216.                     argc -= 2;
  217.                     if (fMinSchedule == 0 || fMaxSchedule == 0 ||
  218.                         fMinSchedule > fMaxSchedule)
  219.                     {
  220.                         fMaxSchedule    = 2500;
  221.                         fMinSchedule    = 1;
  222.                         Printf("WARNING: -m option expects min and max time following\n", str);
  223.                     }
  224.                 }
  225.                 else
  226.                 {
  227.                     Printf("WARNING: Option at and after '-m' not understood!\n", str);
  228.                 }
  229.                 break;
  230.                 
  231.             case 'r':
  232.             case 'R':
  233.                 fResolution = NumToString(argv[idx++]);
  234.                 argc -= 1;
  235.                 break;
  236.                 
  237.             case 'i':
  238.             case 'I':
  239.                 fIterations = NumToString(argv[idx++]);
  240.                 argc -= 1;
  241.                 break;
  242.                 
  243.             case 's':
  244.             case 'S':
  245.                 fStress = true;
  246.                 break;
  247.                 
  248.             default: 
  249.                 argc = 0;
  250.                 Printf("WARNING: Option at and after '%s' not understood!\n", str);
  251.                 break;
  252.         }
  253.  
  254.     }
  255.     if (fStress)
  256.     {
  257.         Printf("\nINFO: Running %u iterations of %u operations, resolution = %u\n",
  258.                fIterations, fNumOperations, fResolution);
  259.         Printf("INFO: Random Schedule from %u to %u milliseconds\n", 
  260.                 fMinSchedule, fMaxSchedule);
  261.     }
  262. }
  263.  
  264. /*******************************************************************************
  265. ** PUBLIC RunStressTest
  266. ********************************************************************************/
  267.  
  268. void TTestTimeScheduler::RunStressTest(Boolean)
  269. {
  270.     size_t                idx, jdx;
  271.     TTimeOperation**    ops;
  272.     unsigned long        sum[3];
  273.     unsigned long        sum2[3];
  274.     unsigned long        total[3];
  275.         
  276.     sum[0] = 0;
  277.     sum[1] = 0;
  278.     sum[2] = 0;
  279.     sum2[0] = 0;
  280.     sum2[1] = 0;
  281.     sum2[2] = 0;
  282.     total[0] = 0;
  283.     total[1] = 0;
  284.     total[2] = 0;
  285.     ops = new TTimeOperation*[fNumOperations];
  286.     if (ops == NULL)
  287.     {
  288.         Printf("ERROR: Out of Memory\n");
  289.         return;
  290.     }
  291.     size_t count = 0;
  292.     for (idx = 0; idx < fNumOperations; ++idx)
  293.     {
  294.         ops[idx] = new TTimeOperation(fTest, idx);
  295.         if (ops[idx])
  296.         {
  297.             ops[idx]->fTest = 30;
  298.             ops[idx]->fWatch = new TStopwatch;
  299.             ops[idx]->fWhen = RandomNumber(fMinSchedule, fMaxSchedule);
  300.             ops[idx]->SetTime(ops[idx]->fWhen);
  301.             if (ops[idx]->fWatch == NULL)
  302.             {
  303.                 delete ops[idx];
  304.                 ops[idx] = NULL;
  305.             }
  306.             else
  307.                 count += 1;
  308.         }
  309.     }
  310.     if (count == 0)
  311.     {
  312.         Printf("ERROR: Out of Memory\n");
  313.         return;
  314.     }
  315.     if (count != fNumOperations)
  316.     {
  317.         Printf("WARNING: Only enough memory to create %u operations\n", count);
  318.     }
  319.     for (jdx = 0; jdx < fNumOperations; ++jdx)
  320.     {
  321.         if (ops[jdx])
  322.             fTest->Schedule(ops[jdx]);
  323.     }
  324.     Printf("       0: ");
  325.     for (idx = 0; idx < fIterations; ++idx)
  326.     {
  327.         Printf(".");
  328.         if ((idx + 1) % 50 == 0)
  329.             Printf("\n%8u: ", idx + 1);
  330.         size_t cnt = 0;
  331.         while (cnt < count)
  332.         {
  333.             for (jdx = 0; jdx < fNumOperations; ++jdx)
  334.             {
  335.                 if (ops[jdx] && ops[jdx]->fFired)
  336.                 {
  337.                     int    diff = ops[jdx]->fDifference;
  338.                     sum[0] += diff;
  339.                     sum2[0] += diff*diff;
  340.                     total[0] += 1;
  341.                     if (diff < 0)
  342.                     {
  343.                         sum[1] -= diff;
  344.                         sum2[1] += diff*diff;
  345.                         total[1] += 1;
  346.                     }
  347.                     else if (diff > 0)
  348.                     {
  349.                         sum[2] += diff;
  350.                         sum2[2] += diff*diff;
  351.                         total[2] += 1;
  352.                     }
  353.                     
  354.                     cnt += 1;
  355.                     ops[jdx]->fFired = false;
  356.                     ops[jdx]->fWhen = RandomNumber(fMinSchedule, fMaxSchedule);
  357.                     ops[jdx]->SetTime(ops[jdx]->fWhen);
  358.                     ops[jdx]->fWatch->Reset();
  359.                     fTest->Schedule(ops[jdx]);
  360.                 }
  361.             }
  362.         }
  363.     }
  364.     Printf("\nEnd of Test\n");
  365.     Printf("Total fired   = %u\n", total[0]);
  366.     Printf("Average error = %u milliseconds\n", sum[0]/total[0]);
  367.     Printf("Variance      = %u\n\n",
  368.            (total[0]*sum2[0] - sum[0]*sum[0])/(total[0]*(total[0] - 1)));
  369.     if (total[1] > 1)
  370.     {
  371.         Printf("Total early fires = %u\n", total[1]);
  372.         Printf("Average error     = %u milliseconds\n", sum[1]/total[1]);
  373.         Printf("Variance          = %u\n\n",
  374.                (total[1]*sum2[1] - sum[1]*sum[1])/(total[1]*(total[1] - 1)));
  375.     }
  376.     if (total[2] > 1)
  377.     {
  378.         Printf("Total late fires = %u\n", total[2]);
  379.         Printf("Average error     = %u milliseconds\n", sum[2]/total[2]);
  380.         Printf("Variance          = %u\n\n",
  381.                (total[2]*sum2[2] - sum[2]*sum[2])/(total[2]*(total[2] - 1)));
  382.     }
  383.     jdx = 0;
  384.     while (jdx < fNumOperations)
  385.     {
  386.         if (ops[jdx] == NULL || ops[jdx]->fFired)
  387.         {
  388.             if (ops[jdx])
  389.             {
  390.                 ops[jdx]->fTest = 9;
  391.                 delete ops[jdx];
  392.             }
  393.             jdx += 1;
  394.         }
  395.     }
  396.     delete ops;
  397. }
  398.  
  399. /**********************************************************************
  400. ** PUBLIC RunTestIteration
  401. ***********************************************************************/
  402.  
  403. void TTestTimeScheduler :: RunTestIteration(Boolean verbose, Boolean)
  404. {
  405.     if (fStress)
  406.     {
  407.         RunStressTest(verbose);
  408.         return;
  409.     }
  410.     
  411.     unsigned short    idx, jdx;
  412.     Boolean            flags[kNumOps];
  413.     TTimeOperation*    ops[kNumOps];
  414.     TStopwatch*        start;
  415.     unsigned long    timers[kNumOps];
  416.     unsigned long    stamps[kNumOps];
  417.     unsigned short    num = kNumOps;
  418.     
  419.     if (verbose)
  420.         Printf("INFO: Creating %u TTimeOperation objects\n", num);
  421.  
  422.     for (idx = 0; idx < num; ++idx)
  423.     {
  424.         ops[idx] = new TTimeOperation(fTest, idx);
  425.         ops[idx]->fTest = 0;
  426.     }
  427.     start = new TStopwatch;
  428.         
  429. /*    -----------------------------------------------------------------
  430.     First, try 1 and 10 milliseconds resolution with a straightforward
  431.     scheduling
  432.     ----------------------------------------------------------------- */
  433.  
  434.     for (idx = 0; idx < 2; ++idx)
  435.     {
  436.         if (verbose)
  437.         {
  438.             Printf("INFO: Testing scheduling ");
  439.             if (idx == 0)
  440.                 Printf("forward   ");
  441.             else
  442.                 Printf("backwards ");
  443.             Printf("  ");
  444.         }
  445.         for (jdx = 0; jdx < num; ++jdx)
  446.         {
  447.             timers[jdx] = jdx*1000 + 1000;
  448.             ops[jdx]->fFired = 0;
  449.             ops[jdx]->SetTime(timers[jdx]);
  450.             flags[jdx] = 0;
  451.         }
  452.         
  453.         start->Reset();
  454.         if (idx != 0)
  455.         {
  456.             for (jdx = 0; jdx < num; ++jdx)
  457.                 fTest->Schedule(ops[num - 1 - jdx]);
  458.         }
  459.         else
  460.             for (jdx = 0; jdx < num; ++jdx)
  461.                 fTest->Schedule(ops[jdx]);
  462.  
  463.         if (fTest->IsEmpty())
  464.             Printf("\n ERROR: TTimeScheduler thinks it is empty when it is not!\n");
  465.  
  466.         Boolean ready = false;
  467.         while (!ready)
  468.         {
  469.             ready = true;
  470.             for (jdx = 0; jdx < num; ++jdx)
  471.                 if (!flags[jdx])
  472.                 {
  473.                     ready = false;
  474.                     break;
  475.                 }
  476.                 
  477.             for (jdx = 0; jdx < num; ++jdx)
  478.                 if (!flags[jdx])
  479.                     if (ops[jdx]->fFired)
  480.                     {
  481.                         flags[jdx] = true;
  482.                         stamps[jdx] = start->ElapsedMilliseconds();
  483.                         Printf(".");
  484.                     }
  485.         }
  486.         Printf("\n");
  487.         for (jdx = 0; jdx < num; ++jdx)
  488.         {
  489.             if (stamps[jdx] < timers[jdx] - kCloseness || stamps[jdx] > timers[jdx] + kCloseness)
  490.                 Printf(" WARNING: Timer%u (%u) fired at T=%u milliseconds\n", jdx + 1, timers[jdx],
  491.                         stamps[jdx]);
  492.         }
  493.     }
  494.     if (!fTest->IsEmpty())
  495.         Printf(" ERROR: TTimeScheduler does not think it is empty!\n");
  496.     for (idx = 0; idx < num - 1; ++idx)
  497.     {
  498.         if (verbose)
  499.             Printf("INFO: Testing Duplicate on #%u  ", idx + 1);
  500.         for (jdx = 0; jdx < num - 1; ++jdx)
  501.                 timers[jdx] = jdx*500 + 500;
  502.         
  503.         timers[num - 1] = timers[idx];
  504.         
  505.         for (jdx = 0; jdx < num; ++jdx)
  506.         {
  507.             ops[jdx]->fFired = 0;
  508.             ops[jdx]->SetTime(timers[jdx]);
  509.             flags[jdx] = 0;
  510.         }
  511.         
  512.         start->Reset();
  513.         for (jdx = 0; jdx < num; ++jdx)
  514.             fTest->Schedule(ops[jdx]);
  515.  
  516.         if (fTest->IsEmpty())
  517.             Printf("\n ERROR: TTimeScheduler thinks it is empty when it is not!\n");
  518.  
  519.         Boolean ready = false;
  520.         while (!ready && start->ElapsedMilliseconds() < timers[num - 2] + 500)
  521.         {
  522.             ready = true;
  523.             for (jdx = 0; jdx < num; ++jdx)
  524.                 if (!flags[jdx])
  525.                 {
  526.                     ready = false;
  527.                     break;
  528.                 }
  529.                 
  530.             short dots = 0;
  531.             for (jdx = 0; jdx < num; ++jdx)
  532.                 if (!flags[jdx])
  533.                     if (ops[jdx]->fFired)
  534.                     {
  535.                         flags[jdx] = true;
  536.                         stamps[jdx] = start->ElapsedMilliseconds();
  537.                         ++dots;
  538.                     }
  539.             while (dots--)
  540.                 Printf(".");
  541.         }
  542.         Printf("\n");
  543.         for (jdx = 0; jdx < num; ++jdx)
  544.         {
  545.             if (stamps[jdx] < timers[jdx] - kCloseness || stamps[jdx] > timers[jdx] + kCloseness)
  546.                 Printf(" WARNING: Timer%u (%u) fired at T=%u milliseconds\n", jdx + 1, timers[jdx],
  547.                         stamps[jdx]);
  548.         }
  549.     }
  550.     if (!fTest->IsEmpty())
  551.         Printf(" ERROR: TTimeScheduler does not think it is empty!\n");
  552.         
  553.     for (idx = 0; idx < num; ++idx)
  554.     {
  555.         if (verbose)
  556.             Printf("INFO: Testing Removal by pointer of #%u  ", idx + 1);
  557.             
  558.         for (jdx = 0; jdx < num; ++jdx)
  559.             timers[jdx] = jdx*500 + 500;
  560.         
  561.         for (jdx = 0; jdx < num; ++jdx)
  562.         {
  563.             ops[jdx]->fFired = 0;
  564.             ops[jdx]->SetTime(timers[jdx]);
  565.             flags[jdx] = 0;
  566.         }
  567.         
  568.         start->Reset();
  569.         for (jdx = 0; jdx < num; ++jdx)
  570.             fTest->Schedule(ops[jdx]);
  571.  
  572.         if (fTest->IsEmpty())
  573.             Printf("\n ERROR: TTimeScheduler thinks it is empty when it is not!\n");
  574.  
  575.         if (!fTest->Remove(ops[idx]))
  576.             Printf("\n ERROR: Removal of Timer #%u failed\n", idx + 1);
  577.             
  578.         Boolean ready = false;
  579.         while (!ready && (idx != num - 1 || start->ElapsedMilliseconds() < timers[num - 1] + 500))
  580.         {
  581.             ready = true;
  582.             for (jdx = 0; jdx < num; ++jdx)
  583.                 if (jdx != idx)
  584.                     if (!flags[jdx])
  585.                     {
  586.                         ready = false;
  587.                         break;
  588.                     }
  589.                 
  590.             for (jdx = 0; jdx < num; ++jdx)
  591.                 if (!flags[jdx])
  592.                     if (ops[jdx]->fFired)
  593.                     {
  594.                         flags[jdx] = true;
  595.                         stamps[jdx] = start->ElapsedMilliseconds();
  596.                         Printf(".");
  597.                         if (jdx == idx)
  598.                             Printf("\n ERROR: Bummer - Timer #%u Fired\n", jdx + 1);
  599.                     }
  600.         }
  601.         Printf("\n");
  602.         for (jdx = 0; jdx < num; ++jdx)
  603.         {
  604.             if (ops[jdx]->fFired == 0)
  605.                 continue;
  606.             if (stamps[jdx] < timers[jdx] - kCloseness || stamps[jdx] > timers[jdx] + kCloseness)
  607.                 Printf(" WARNING: Timer%u (%u) fired at T=%u milliseconds\n", jdx + 1, timers[jdx],
  608.                         stamps[jdx]);
  609.         }
  610.         if (!fTest->IsEmpty())
  611.             Printf(" ERROR: TTimeScheduler does not think it is empty!\n");
  612.     }
  613.     
  614.     for (idx = 0; idx < num; ++idx)
  615.     {
  616.         TTimeMatcher    match(idx);
  617.         
  618.         if (verbose)
  619.             Printf("INFO: Testing Removal by matchObject of #%u  ", idx + 1);
  620.             
  621.         for (jdx = 0; jdx < num; ++jdx)
  622.             timers[jdx] = jdx*500 + 500;
  623.         
  624.         for (jdx = 0; jdx < num; ++jdx)
  625.         {
  626.             ops[jdx]->fFired = 0;
  627.             ops[jdx]->SetTime(timers[jdx]);
  628.             flags[jdx] = 0;
  629.         }
  630.         
  631.         start->Reset();
  632.         for (jdx = 0; jdx < num; ++jdx)
  633.             fTest->Schedule(ops[jdx]);
  634.  
  635.         if (fTest->IsEmpty())
  636.             Printf("\n ERROR: TTimeScheduler thinks it is empty when it is not!\n");
  637.  
  638.         TOperation* op = fTest->Remove(match);
  639.         if (!op)
  640.             Printf("\n ERROR: Removal of Timer #%u failed\n", idx + 1);
  641.         if (op != ops[idx])
  642.             Printf("\n ERROR: Removal of Timer #%u did not return the correct operation\n", idx + 1);
  643.             
  644.         Boolean ready = false;
  645.         while (!ready && (idx != num - 1 || start->ElapsedMilliseconds() < timers[num - 1] + 500))
  646.         {
  647.             ready = true;
  648.             for (jdx = 0; jdx < num; ++jdx)
  649.                 if (jdx != idx)
  650.                     if (!flags[jdx])
  651.                     {
  652.                         ready = false;
  653.                         break;
  654.                     }
  655.                 
  656.             for (jdx = 0; jdx < num; ++jdx)
  657.                 if (!flags[jdx])
  658.                     if (ops[jdx]->fFired)
  659.                     {
  660.                         flags[jdx] = true;
  661.                         stamps[jdx] = start->ElapsedMilliseconds();
  662.                         Printf(".");
  663.                         if (jdx == idx)
  664.                             Printf("\n ERROR: Bummer - Timer #%u Fired\n", jdx + 1);
  665.                     }
  666.         }
  667.         Printf("\n");
  668.         for (jdx = 0; jdx < num; ++jdx)
  669.         {
  670.             if (ops[jdx]->fFired == 0)
  671.                 continue;
  672.             if (stamps[jdx] < timers[jdx] - kCloseness || stamps[jdx] > timers[jdx] + kCloseness)
  673.                 Printf(" WARNING: Timer%u (%u) fired at T=%u milliseconds\n", jdx + 1, timers[jdx],
  674.                         stamps[jdx]);
  675.         }
  676.         if (!fTest->IsEmpty())
  677.             Printf(" ERROR: TTimeScheduler does not think it is empty!\n");
  678.     }
  679.     
  680.     
  681.     for (idx = 0; idx < num; ++idx)
  682.     {
  683.         if (verbose)
  684.             Printf("INFO: Testing Removal/Acknowledge while in Process of #%u  ", idx + 1);
  685.             
  686.         for (jdx = 0; jdx < num; ++jdx)
  687.             timers[jdx] = jdx*500 + 500;
  688.         
  689.         for (jdx = 0; jdx < num; ++jdx)
  690.         {
  691.             ops[jdx]->fFired = 0;
  692.             ops[jdx]->fTest = 0;
  693.             ops[jdx]->SetTime(timers[jdx]);
  694.             flags[jdx] = 0;
  695.         }
  696.         ops[idx]->fTest = 1;
  697.         
  698.         start->Reset();
  699.         for (jdx = 0; jdx < num; ++jdx)
  700.             fTest->Schedule(ops[jdx]);
  701.  
  702.         if (fTest->IsEmpty())
  703.             Printf("\n ERROR: TTimeScheduler thinks it is empty when it is not!\n");
  704.  
  705.         Boolean ready = false;
  706.         while (!ready)
  707.         {
  708.             ready = true;
  709.             for (jdx = 0; jdx < num; ++jdx)
  710.                 if (!flags[jdx])
  711.                 {
  712.                     ready = false;
  713.                     break;
  714.                 }
  715.                 
  716.             for (jdx = 0; jdx < num; ++jdx)
  717.                 if (!flags[jdx])
  718.                     if (ops[jdx]->fFired)
  719.                     {
  720.                         flags[jdx] = true;
  721.                         stamps[jdx] = start->ElapsedMilliseconds();
  722.                         Printf(".");
  723.                     }
  724.         }
  725.         Printf("\n");
  726.         if (!fTest->IsEmpty())
  727.             Printf(" ERROR: TTimeScheduler does not think it is empty!\n");
  728.     }
  729.     
  730.     for (idx = 0; idx < num; ++idx)
  731.     {
  732.         if (verbose)
  733.             Printf("INFO: Testing Removal/Rerun while in Process of #%u  ", idx + 1);
  734.             
  735.         for (jdx = 0; jdx < num; ++jdx)
  736.             timers[jdx] = jdx*500 + 500;
  737.         
  738.         for (jdx = 0; jdx < num; ++jdx)
  739.         {
  740.             ops[jdx]->fFired = 0;
  741.             ops[jdx]->fTest = 0;
  742.             ops[jdx]->SetTime(timers[jdx]);
  743.             flags[jdx] = 0;
  744.         }
  745.         ops[idx]->fTest = 2;
  746.         
  747.         start->Reset();
  748.         for (jdx = 0; jdx < num; ++jdx)
  749.             fTest->Schedule(ops[jdx]);
  750.  
  751.         if (fTest->IsEmpty())
  752.             Printf("\n ERROR: TTimeScheduler thinks it is empty when it is not!\n");
  753.  
  754.         Boolean ready = false;
  755.         while (!ready)
  756.         {
  757.             ready = true;
  758.             for (jdx = 0; jdx < num; ++jdx)
  759.                 if (!flags[jdx])
  760.                 {
  761.                     ready = false;
  762.                     break;
  763.                 }
  764.                 
  765.             for (jdx = 0; jdx < num; ++jdx)
  766.                 if (!flags[jdx])
  767.                     if (ops[jdx]->fFired)
  768.                     {
  769.                         flags[jdx] = true;
  770.                         stamps[jdx] = start->ElapsedMilliseconds();
  771.                         Printf(".");
  772.                     }
  773.         }
  774.         Printf("\n");
  775.         if (!fTest->IsEmpty())
  776.             Printf(" ERROR: TTimeScheduler does not think it is empty!\n");
  777.     }
  778.     
  779.     
  780.     if (verbose)
  781.         Printf("INFO: Testing single Reschedule\n");
  782.     timers[0] = 1000;
  783.     ops[0]->fFired = 0;
  784.     ops[0]->fTest = 0;
  785.     ops[0]->SetTime(timers[0]);
  786.     flags[0] = 0;
  787.     start->Reset();
  788.     fTest->Schedule(ops[0]);
  789.     if (fTest->IsEmpty())
  790.         Printf("ERROR: TTimeScheduler thinks it is empty when it is not!\n");
  791.     if (!fTest->Remove(ops[0]))
  792.         Printf("ERROR: could not remove the TOperation!\n");
  793.     else
  794.     {
  795.         ops[0]->SetTime(3000);
  796.         timers[0] = 3000;
  797.         fTest->Schedule(ops[0]);
  798.     }
  799.     while (ops[0]->fFired == 0)
  800.         ;
  801.     stamps[0] = start->ElapsedMilliseconds();
  802.     if (stamps[0] < 3000 - kCloseness || stamps[0] > 3000 + kCloseness)
  803.     {
  804.         Printf("WARNING: Timer fired at %u\n", stamps[0]);
  805.     }
  806.         
  807.     for (idx = 0; idx < num; ++idx)
  808.     {
  809.         if (verbose)
  810.             Printf("INFO: Testing Reschedule while in Process of #%u  ", idx + 1);
  811.             
  812.         for (jdx = 0; jdx < num; ++jdx)
  813.             timers[jdx] = jdx*500 + 500;
  814.         
  815.         for (jdx = 0; jdx < num; ++jdx)
  816.         {
  817.             ops[jdx]->fFired = 0;
  818.             ops[jdx]->fTest = 0;
  819.             ops[jdx]->SetTime(timers[jdx]);
  820.             flags[jdx] = 0;
  821.         }
  822.         ops[idx]->fTest = 4;
  823.         
  824.         start->Reset();
  825.         for (jdx = 0; jdx < num; ++jdx)
  826.             fTest->Schedule(ops[jdx]);
  827.  
  828.         if (fTest->IsEmpty())
  829.             Printf("\n ERROR: TTimeScheduler thinks it is empty when it is not!\n");
  830.  
  831.         Boolean ready = false;
  832.         while (!ready)
  833.         {
  834.             ready = true;
  835.             for (jdx = 0; jdx < num; ++jdx)
  836.                 if (!flags[jdx])
  837.                 {
  838.                     ready = false;
  839.                     break;
  840.                 }
  841.                 
  842.             for (jdx = 0; jdx < num; ++jdx)
  843.                 if (!flags[jdx])
  844.                     if (ops[jdx]->fFired)
  845.                     {
  846.                         flags[jdx] = true;
  847.                         stamps[jdx] = start->ElapsedMilliseconds();
  848.                         Printf(".");
  849.                     }
  850.         }
  851.         while (ops[idx]->fTest != 20 && start->ElapsedMilliseconds() < num*1000)
  852.             ;
  853.         stamps[idx] = start->ElapsedMilliseconds();
  854.         Printf("\n");
  855.         if (ops[idx]->fTest != 20)
  856.             Printf(" ERROR: Timer#%u did not fire a second time\n", idx + 1);
  857.         else
  858.             if (stamps[idx] < 3500 - kCloseness || stamps[idx] > 3500 + kCloseness)
  859.             {
  860.                 Printf(" WARNING: Timer#%u (%u) fired at %u\n",
  861.                        idx + 1, 3500, stamps[idx]);
  862.             }
  863.         if (!fTest->IsEmpty())
  864.             Printf(" ERROR: TTimeScheduler does not think it is empty!\n");
  865.     }
  866.     
  867.     for (idx = 0; idx < num; ++idx)
  868.     {
  869.         if (verbose)
  870.             Printf("INFO: Testing Remove/Reschedule while in Process of #%u  ", idx + 1);
  871.             
  872.         for (jdx = 0; jdx < num; ++jdx)
  873.             timers[jdx] = jdx*500 + 500;
  874.         
  875.         for (jdx = 0; jdx < num; ++jdx)
  876.         {
  877.             ops[jdx]->fFired = 0;
  878.             ops[jdx]->fTest = 0;
  879.             ops[jdx]->SetTime(timers[jdx]);
  880.             flags[jdx] = 0;
  881.         }
  882.         ops[idx]->fTest = 6;
  883.         
  884.         start->Reset();
  885.         for (jdx = 0; jdx < num; ++jdx)
  886.             fTest->Schedule(ops[jdx]);
  887.  
  888.         if (fTest->IsEmpty())
  889.             Printf("\n ERROR: TTimeScheduler thinks it is empty when it is not!\n");
  890.  
  891.         Boolean ready = false;
  892.         while (!ready)
  893.         {
  894.             ready = true;
  895.             for (jdx = 0; jdx < num; ++jdx)
  896.                 if (!flags[jdx])
  897.                 {
  898.                     ready = false;
  899.                     break;
  900.                 }
  901.                 
  902.             for (jdx = 0; jdx < num; ++jdx)
  903.                 if (!flags[jdx])
  904.                     if (ops[jdx]->fFired)
  905.                     {
  906.                         flags[jdx] = true;
  907.                         stamps[jdx] = start->ElapsedMilliseconds();
  908.                         Printf(".");
  909.                     }
  910.         }
  911.         Printf("\n");
  912.         if (!fTest->IsEmpty())
  913.         {
  914.             Printf(" ERROR: TTimeScheduler does not think it is empty!\n");
  915.             while (ops[idx]->fTest != 21 && start->ElapsedMilliseconds() < num*1000)
  916.                 ;
  917.             if (ops[idx]->fTest == 21)
  918.                 Printf(" ERROR: Timer#%u fired a second time\n", idx + 1);
  919.         }
  920.     }
  921.  
  922.     if (verbose)
  923.         Printf("INFO: Testing Removal/Delete  ", idx + 1);
  924.         
  925.     for (jdx = 0; jdx < num; ++jdx)
  926.         timers[jdx] = jdx*500 + 500;
  927.     
  928.     for (jdx = 0; jdx < num; ++jdx)
  929.     {
  930.         ops[jdx]->fFired = 0;
  931.         ops[jdx]->fTest = 8;
  932.         ops[jdx]->SetTime(timers[jdx]);
  933.         flags[jdx] = 0;
  934.     }
  935.     
  936.     start->Reset();
  937.     for (jdx = 0; jdx < num; ++jdx)
  938.         fTest->Schedule(ops[jdx]);
  939.  
  940.     if (fTest->IsEmpty())
  941.         Printf("\n ERROR: TTimeScheduler thinks it is empty when it is not!\n");
  942.  
  943.     Boolean ready = false;
  944.     while (!ready)
  945.     {
  946.         ready = true;
  947.         for (jdx = 0; jdx < num; ++jdx)
  948.             if (!flags[jdx])
  949.             {
  950.                 ready = false;
  951.                 break;
  952.             }
  953.             
  954.         for (jdx = 0; jdx < num; ++jdx)
  955.             if (!flags[jdx])
  956.                 if (ops[jdx]->fFired)
  957.                 {
  958.                     flags[jdx] = true;
  959.                     stamps[jdx] = start->ElapsedMilliseconds();
  960.                     Printf(".");
  961.                 }
  962.     }
  963.     Printf("\n");
  964.     for (jdx = 0; jdx < num; ++jdx)
  965.     {
  966.         if (ops[jdx]->fTest != 10)
  967.             Printf("ERROR: Timer%u (%u) did not delete itself\n", jdx + 1, timers[jdx]);
  968.         if (ops[jdx]->fFired == 0)
  969.             continue;
  970.     }
  971.     if (!fTest->IsEmpty())
  972.         Printf(" ERROR: TTimeScheduler does not think it is empty!\n");
  973.  
  974.     delete start;
  975. }
  976.  
  977. /**********************************************************************
  978. ** PUBLIC EndTest
  979. ***********************************************************************/
  980.  
  981. void TTestTimeScheduler :: EndTest(Boolean, Boolean)
  982. {
  983.     delete fTest;
  984.     fTest = NULL;
  985. }
  986.