mux/src/timer.cpp

Go to the documentation of this file.
00001 // timer.cpp -- Mini-task scheduler for timed events.
00002 //
00003 // $Id: timer.cpp,v 1.20 2007/02/03 04:25:46 sdennis Exp $
00004 //
00005 // MUX 2.4
00006 // Copyright (C) 1998 through 2004 Solid Vertical Domains, Ltd. All
00007 // rights not explicitly given are reserved.
00008 //
00009 #include "copyright.h"
00010 #include "autoconf.h"
00011 #include "config.h"
00012 #include "externs.h"
00013 
00014 #include <signal.h>
00015 
00016 #include "command.h"
00017 #include "mguests.h"
00018 
00019 CScheduler scheduler;
00020 
00021 // Free List Reconstruction Task routine.
00022 //
00023 void dispatch_FreeListReconstruction(void *pUnused, int iUnused)
00024 {
00025     UNUSED_PARAMETER(pUnused);
00026     UNUSED_PARAMETER(iUnused);
00027 
00028     if (mudconf.control_flags & CF_DBCHECK)
00029     {
00030         char *cmdsave = mudstate.debug_cmd;
00031         mudstate.debug_cmd = (char *)"< dbck >";
00032         do_dbck(NOTHING, NOTHING, NOTHING, 0);
00033         Guest.CleanUp();
00034         pcache_trim();
00035         pool_reset();
00036         mudstate.debug_cmd = cmdsave;
00037     }
00038 
00039     // Schedule ourselves again.
00040     //
00041     CLinearTimeAbsolute ltaNow;
00042     ltaNow.GetUTC();
00043     CLinearTimeDelta ltd;
00044     ltd.SetSeconds(mudconf.check_interval);
00045     mudstate.check_counter = ltaNow + ltd;
00046     scheduler.DeferTask(mudstate.check_counter, PRIORITY_SYSTEM,
00047         dispatch_FreeListReconstruction, 0, 0);
00048 }
00049 
00050 // Database Dump Task routine.
00051 //
00052 void dispatch_DatabaseDump(void *pUnused, int iUnused)
00053 {
00054     UNUSED_PARAMETER(pUnused);
00055     UNUSED_PARAMETER(iUnused);
00056 
00057     int nNextTimeInSeconds = mudconf.dump_interval;
00058 
00059     if (mudconf.control_flags & CF_CHECKPOINT)
00060     {
00061         char *cmdsave = mudstate.debug_cmd;
00062         mudstate.debug_cmd = (char *)"< dump >";
00063 #ifndef WIN32
00064         if (mudstate.dumping)
00065         {
00066             // There is a dump in progress. These usually happen very quickly.
00067             // We will reschedule ourselves to try again in 20 seconds.
00068             // Ordinarily, you would think "...a dump is a dump...", but some
00069             // dumps might not be the type of dump we're going to do.
00070             //
00071             nNextTimeInSeconds = 20;
00072         }
00073         else
00074 #endif // !WIN32
00075         {
00076             fork_and_dump(0);
00077         }
00078         mudstate.debug_cmd = cmdsave;
00079     }
00080 
00081     // Schedule ourselves again.
00082     //
00083     CLinearTimeAbsolute ltaNow;
00084     ltaNow.GetUTC();
00085     CLinearTimeDelta ltd;
00086     ltd.SetSeconds(nNextTimeInSeconds);
00087     mudstate.dump_counter = ltaNow + ltd;
00088     scheduler.DeferTask(mudstate.dump_counter, PRIORITY_SYSTEM, dispatch_DatabaseDump, 0, 0);
00089 }
00090 
00091 // Idle Check Task routine.
00092 //
00093 void dispatch_IdleCheck(void *pUnused, int iUnused)
00094 {
00095     UNUSED_PARAMETER(pUnused);
00096     UNUSED_PARAMETER(iUnused);
00097 
00098     if (mudconf.control_flags & CF_IDLECHECK)
00099     {
00100         char *cmdsave = mudstate.debug_cmd;
00101         mudstate.debug_cmd = (char *)"< idlecheck >";
00102         check_idle();
00103         mudstate.debug_cmd = cmdsave;
00104     }
00105 
00106     // Schedule ourselves again.
00107     //
00108     CLinearTimeAbsolute ltaNow;
00109     ltaNow.GetUTC();
00110     CLinearTimeDelta ltd;
00111     ltd.SetSeconds(mudconf.idle_interval);
00112     mudstate.idle_counter = ltaNow + ltd;
00113     scheduler.DeferTask(mudstate.idle_counter, PRIORITY_SYSTEM, dispatch_IdleCheck, 0, 0);
00114 }
00115 
00116 // Check Events Task routine.
00117 //
00118 void dispatch_CheckEvents(void *pUnused, int iUnused)
00119 {
00120     UNUSED_PARAMETER(pUnused);
00121     UNUSED_PARAMETER(iUnused);
00122 
00123     if (mudconf.control_flags & CF_EVENTCHECK)
00124     {
00125         char *cmdsave = mudstate.debug_cmd;
00126         mudstate.debug_cmd = (char *)"< eventcheck >";
00127         check_events();
00128         mudstate.debug_cmd = cmdsave;
00129     }
00130 
00131     // Schedule ourselves again.
00132     //
00133     CLinearTimeAbsolute ltaNow;
00134     ltaNow.GetUTC();
00135     CLinearTimeDelta ltd = time_15m;
00136     mudstate.events_counter = ltaNow + ltd;
00137     scheduler.DeferTask(mudstate.events_counter, PRIORITY_SYSTEM, dispatch_CheckEvents, 0, 0);
00138 }
00139 
00140 #ifndef MEMORY_BASED
00141 void dispatch_CacheTick(void *pUnused, int iUnused)
00142 {
00143     UNUSED_PARAMETER(pUnused);
00144     UNUSED_PARAMETER(iUnused);
00145 
00146     char *cmdsave = mudstate.debug_cmd;
00147     mudstate.debug_cmd = (char *)"< cachetick >";
00148 
00149     CLinearTimeDelta ltd = 0;
00150     if (mudconf.cache_tick_period <= ltd)
00151     {
00152         mudconf.cache_tick_period.SetSeconds(1);
00153     }
00154 
00155     cache_tick();
00156 
00157     // Schedule ourselves again.
00158     //
00159     CLinearTimeAbsolute ltaNextTime;
00160     ltaNextTime.GetUTC();
00161     ltaNextTime += mudconf.cache_tick_period;
00162     scheduler.DeferTask(ltaNextTime, PRIORITY_SYSTEM, dispatch_CacheTick, 0, 0);
00163     mudstate.debug_cmd = cmdsave;
00164 }
00165 #endif // !MEMORY_BASED
00166 
00167 #if 0
00168 void dispatch_CleanChannels(void *pUnused, int iUnused)
00169 {
00170     char *cmdsave = mudstate.debug_cmd;
00171     mudstate.debug_cmd = (char *)"< cleanchannels >";
00172     do_cleanupchannels();
00173 
00174     // Schedule ourselves again.
00175     //
00176     CLinearTimeAbsolute ltaNextTime;
00177     ltaNextTime.GetUTC();
00178     CLinearTimeDelta ltd = time_15m;
00179     ltaNextTime += ltd;
00180     scheduler.DeferTask(ltaNextTime, PRIORITY_SYSTEM, dispatch_CleanChannels, 0, 0);
00181     mudstate.debug_cmd = cmdsave;
00182 }
00183 #endif // 0
00184 
00185 static void dispatch_CanRestart(void *pUnused, int iUnused)
00186 {
00187     UNUSED_PARAMETER(pUnused);
00188     UNUSED_PARAMETER(iUnused);
00189     mudstate.bCanRestart = true;
00190 }
00191 
00192 #ifdef WIN32
00193 static void dispatch_CalibrateQueryPerformance(void *pUnused, int iUnused)
00194 {
00195     UNUSED_PARAMETER(pUnused);
00196     UNUSED_PARAMETER(iUnused);
00197 
00198     CLinearTimeAbsolute ltaNextTime;
00199     ltaNextTime.GetUTC();
00200     CLinearTimeDelta ltd = time_30s;
00201     ltaNextTime += ltd;
00202 
00203     if (CalibrateQueryPerformance())
00204     {
00205         scheduler.DeferTask(ltaNextTime, PRIORITY_SYSTEM,
00206             dispatch_CalibrateQueryPerformance, 0, 0);
00207     }
00208 }
00209 #endif // WIN32
00210 
00211 void init_timer(void)
00212 {
00213     CLinearTimeAbsolute ltaNow;
00214     ltaNow.GetUTC();
00215 
00216     // Setup re-occuring Free List Reconstruction task.
00217     //
00218     CLinearTimeDelta ltd;
00219     ltd.SetSeconds((mudconf.check_offset == 0) ? mudconf.check_interval : mudconf.check_offset);
00220     mudstate.check_counter  = ltaNow + ltd;
00221     scheduler.DeferTask(mudstate.check_counter, PRIORITY_SYSTEM,
00222         dispatch_FreeListReconstruction, 0, 0);
00223 
00224     // Setup re-occuring Database Dump task.
00225     //
00226     ltd.SetSeconds((mudconf.dump_offset == 0) ? mudconf.dump_interval : mudconf.dump_offset);
00227     mudstate.dump_counter  = ltaNow + ltd;
00228     scheduler.DeferTask(mudstate.dump_counter, PRIORITY_SYSTEM,
00229         dispatch_DatabaseDump, 0, 0);
00230 
00231     // Setup re-occuring Idle Check task.
00232     //
00233     ltd.SetSeconds(mudconf.idle_interval);
00234     mudstate.idle_counter   = ltaNow + ltd;
00235     scheduler.DeferTask(mudstate.idle_counter, PRIORITY_SYSTEM,
00236         dispatch_IdleCheck, 0, 0);
00237 
00238     // Setup re-occuring Check Events task.
00239     //
00240     mudstate.events_counter = ltaNow + time_15s;
00241     scheduler.DeferTask(mudstate.events_counter, PRIORITY_SYSTEM,
00242         dispatch_CheckEvents, 0, 0);
00243 
00244 #ifndef MEMORY_BASED
00245     // Setup re-occuring cache_tick task.
00246     //
00247     ltd.SetSeconds(0);
00248     if (mudconf.cache_tick_period <= ltd)
00249     {
00250         mudconf.cache_tick_period.SetSeconds(1);
00251     }
00252     scheduler.DeferTask(ltaNow+mudconf.cache_tick_period, PRIORITY_SYSTEM,
00253         dispatch_CacheTick, 0, 0);
00254 #endif // !MEMORY_BASED
00255 
00256 #if 0
00257     // Setup comsys channel scrubbing.
00258     //
00259     scheduler.DeferTask(ltaNow+time_45s, PRIORITY_SYSTEM, dispatch_CleanChannels, 0, 0);
00260 #endif // 0
00261 
00262     // Setup one-shot task to enable restarting 10 seconds after startmux.
00263     //
00264     scheduler.DeferTask(ltaNow+time_15s, PRIORITY_OBJECT, dispatch_CanRestart, 0, 0);
00265 
00266 #ifdef WIN32
00267     // Setup Periodic QueryPerformance Calibration.
00268     //
00269     scheduler.DeferTask(ltaNow+time_30s, PRIORITY_SYSTEM,
00270         dispatch_CalibrateQueryPerformance, 0, 0);
00271 
00272 #endif // WIN32
00273 }
00274 
00275 /*
00276  * ---------------------------------------------------------------------------
00277  * * do_timewarp: Adjust various internal timers.
00278  */
00279 
00280 void do_timewarp(dbref executor, dbref caller, dbref enactor, int key, char *arg)
00281 {
00282     int secs;
00283 
00284     secs = mux_atol(arg);
00285 
00286     // Sem/Wait queues
00287     //
00288     if ((key == 0) || (key & TWARP_QUEUE))
00289     {
00290         do_queue(executor, caller, enactor, QUEUE_WARP, arg);
00291     }
00292 
00293     // Once these are adjusted, we need to Cancel and reschedule the task.
00294     //
00295     CLinearTimeDelta ltd;
00296     ltd.SetSeconds(secs);
00297     if (key & TWARP_DUMP)
00298     {
00299         mudstate.dump_counter -= ltd;
00300         scheduler.CancelTask(dispatch_DatabaseDump, 0, 0);
00301         scheduler.DeferTask(mudstate.dump_counter, PRIORITY_SYSTEM, dispatch_DatabaseDump, 0, 0);
00302     }
00303     if (key & TWARP_CLEAN)
00304     {
00305         mudstate.check_counter -= ltd;
00306         scheduler.CancelTask(dispatch_FreeListReconstruction, 0, 0);
00307         scheduler.DeferTask(mudstate.check_counter, PRIORITY_SYSTEM, dispatch_FreeListReconstruction, 0, 0);
00308     }
00309     if (key & TWARP_IDLE)
00310     {
00311         mudstate.idle_counter -= ltd;
00312         scheduler.CancelTask(dispatch_IdleCheck, 0, 0);
00313         scheduler.DeferTask(mudstate.idle_counter, PRIORITY_SYSTEM, dispatch_IdleCheck, 0, 0);
00314     }
00315     if (key & TWARP_EVENTS)
00316     {
00317         mudstate.events_counter -= ltd;
00318         scheduler.CancelTask(dispatch_CheckEvents, 0, 0);
00319         scheduler.DeferTask(mudstate.events_counter, PRIORITY_SYSTEM, dispatch_CheckEvents, 0, 0);
00320     }
00321 }
00322 
00323 #define INITIAL_TASKS 100
00324 #define EXTRA_TASKS    50
00325 
00326 CTaskHeap::CTaskHeap(void)
00327 {
00328     m_nCurrent = 0;
00329     m_iVisitedMark = 0;
00330     m_nAllocated = INITIAL_TASKS;
00331     m_pHeap = new PTASK_RECORD[m_nAllocated];
00332     if (!m_pHeap)
00333     {
00334         m_nAllocated = 0;
00335     }
00336 }
00337 
00338 CTaskHeap::~CTaskHeap(void)
00339 {
00340     while (m_nCurrent--)
00341     {
00342         PTASK_RECORD pTask = m_pHeap[m_nCurrent];
00343         if (pTask)
00344         {
00345             delete pTask;
00346         }
00347         m_pHeap[m_nCurrent] = NULL;
00348     }
00349     if (m_pHeap)
00350     {
00351         delete [] m_pHeap;
00352     }
00353 }
00354 
00355 bool CTaskHeap::Insert(PTASK_RECORD pTask, SCHCMP *pfCompare)
00356 {
00357     if (m_nCurrent == m_nAllocated)
00358     {
00359         if (!Grow())
00360         {
00361             return false;
00362         }
00363     }
00364     pTask->m_iVisitedMark = m_iVisitedMark-1;
00365 
00366     m_pHeap[m_nCurrent] = pTask;
00367     m_nCurrent++;
00368     SiftUp(m_nCurrent-1, pfCompare);
00369     return true;
00370 }
00371 
00372 bool CTaskHeap::Grow(void)
00373 {
00374     // Grow the heap.
00375     //
00376     int n = m_nAllocated + EXTRA_TASKS;
00377     PTASK_RECORD *p = new PTASK_RECORD[n];
00378     if (!p)
00379     {
00380         return false;
00381     }
00382 
00383     memcpy(p, m_pHeap, sizeof(PTASK_RECORD)*m_nAllocated);
00384     m_nAllocated = n;
00385     delete [] m_pHeap;
00386     m_pHeap = p;
00387 
00388     return true;
00389 }
00390 
00391 PTASK_RECORD CTaskHeap::PeekAtTopmost(void)
00392 {
00393     if (m_nCurrent <= 0)
00394     {
00395         return NULL;
00396     }
00397     return m_pHeap[0];
00398 }
00399 
00400 PTASK_RECORD CTaskHeap::RemoveTopmost(SCHCMP *pfCompare)
00401 {
00402     return Remove(0, pfCompare);
00403 }
00404 
00405 void CTaskHeap::CancelTask(FTASK *fpTask, void *arg_voidptr, int arg_Integer)
00406 {
00407     for (int i = 0; i < m_nCurrent; i++)
00408     {
00409         PTASK_RECORD p = m_pHeap[i];
00410         if (  p->fpTask == fpTask
00411            && p->arg_voidptr == arg_voidptr
00412            && p->arg_Integer == arg_Integer)
00413         {
00414             p->fpTask = NULL;
00415         }
00416     }
00417 }
00418 
00419 static int ComparePriority(PTASK_RECORD pTaskA, PTASK_RECORD pTaskB)
00420 {
00421     int i = (pTaskA->iPriority) - (pTaskB->iPriority);
00422     if (i == 0)
00423     {
00424         // Must subtract so that ticket rollover is handled properly.
00425         //
00426         return  (pTaskA->m_Ticket) - (pTaskB->m_Ticket);
00427     }
00428     return i;
00429 }
00430 
00431 static int CompareWhen(PTASK_RECORD pTaskA, PTASK_RECORD pTaskB)
00432 {
00433     // Can't simply subtract because comparing involves a truncation cast.
00434     //
00435     if (pTaskA->ltaWhen < pTaskB->ltaWhen)
00436     {
00437         return -1;
00438     }
00439     else if (pTaskA->ltaWhen > pTaskB->ltaWhen)
00440     {
00441         return 1;
00442     }
00443     return 0;
00444 }
00445 
00446 void CScheduler::DeferTask(const CLinearTimeAbsolute& ltaWhen, int iPriority,
00447                            FTASK *fpTask, void *arg_voidptr, int arg_Integer)
00448 {
00449     PTASK_RECORD pTask = new TASK_RECORD;
00450     if (!pTask) return;
00451 
00452     pTask->ltaWhen = ltaWhen;
00453     pTask->iPriority = iPriority;
00454     pTask->fpTask = fpTask;
00455     pTask->arg_voidptr = arg_voidptr;
00456     pTask->arg_Integer = arg_Integer;
00457     pTask->m_Ticket = m_Ticket++;
00458 
00459     // Must add to the WhenHeap so that network is still serviced.
00460     //
00461     if (!m_WhenHeap.Insert(pTask, CompareWhen))
00462     {
00463         delete pTask;
00464     }
00465 }
00466 
00467 void CScheduler::DeferImmediateTask(int iPriority, FTASK *fpTask, void *arg_voidptr, int arg_Integer)
00468 {
00469     PTASK_RECORD pTask = new TASK_RECORD;
00470     if (!pTask) return;
00471 
00472     //pTask->ltaWhen = ltaWhen;
00473     pTask->iPriority = iPriority;
00474     pTask->fpTask = fpTask;
00475     pTask->arg_voidptr = arg_voidptr;
00476     pTask->arg_Integer = arg_Integer;
00477     pTask->m_Ticket = m_Ticket++;
00478 
00479     // Must add to the WhenHeap so that network is still serviced.
00480     //
00481     if (!m_WhenHeap.Insert(pTask, CompareWhen))
00482     {
00483         delete pTask;
00484     }
00485 }
00486 
00487 void CScheduler::CancelTask(FTASK *fpTask, void *arg_voidptr, int arg_Integer)
00488 {
00489     m_WhenHeap.CancelTask(fpTask, arg_voidptr, arg_Integer);
00490     m_PriorityHeap.CancelTask(fpTask, arg_voidptr, arg_Integer);
00491 }
00492 
00493 void CScheduler::ReadyTasks(const CLinearTimeAbsolute& ltaNow)
00494 {
00495     // Move ready-to-run tasks off the WhenHeap and onto the PriorityHeap.
00496     //
00497     PTASK_RECORD pTask = m_WhenHeap.PeekAtTopmost();
00498     while (  pTask
00499           && pTask->ltaWhen < ltaNow)
00500     {
00501         pTask = m_WhenHeap.RemoveTopmost(CompareWhen);
00502         if (pTask)
00503         {
00504             if (  NULL == pTask->fpTask
00505                || !m_PriorityHeap.Insert(pTask, ComparePriority))
00506             {
00507                 delete pTask;
00508             }
00509         }
00510         pTask = m_WhenHeap.PeekAtTopmost();
00511     }
00512 }
00513 
00514 int CScheduler::RunTasks(const CLinearTimeAbsolute& ltaNow)
00515 {
00516     ReadyTasks(ltaNow);
00517     if (mudconf.active_q_chunk)
00518     {
00519         return RunTasks(mudconf.active_q_chunk);
00520     }
00521     else
00522     {
00523         return RunAllTasks();
00524     }
00525 }
00526 
00527 int CScheduler::RunTasks(int iCount)
00528 {
00529     int nTasks = 0;
00530     while (iCount--)
00531     {
00532         PTASK_RECORD pTask = m_PriorityHeap.PeekAtTopmost();
00533         if (!pTask) break;
00534 
00535         if (pTask->iPriority > m_minPriority)
00536         {
00537             // This is related to CF_DEQUEUE and also to untimed (SUSPENDED)
00538             // semaphore entries that we would like to manage together with
00539             // the timed ones.
00540             //
00541             break;
00542         }
00543         pTask = m_PriorityHeap.RemoveTopmost(ComparePriority);
00544         if (pTask)
00545         {
00546             if (pTask->fpTask)
00547             {
00548                 pTask->fpTask(pTask->arg_voidptr, pTask->arg_Integer);
00549                 nTasks++;
00550             }
00551             delete pTask;
00552         }
00553     }
00554     return nTasks;
00555 }
00556 
00557 int CScheduler::RunAllTasks(void)
00558 {
00559     int nTotalTasks = 0;
00560 
00561     int nTasks;
00562     do
00563     {
00564         nTasks = RunTasks(100);
00565         nTotalTasks += nTasks;
00566     } while (nTasks);
00567 
00568     return nTotalTasks;
00569 }
00570 
00571 bool CScheduler::WhenNext(CLinearTimeAbsolute  *ltaWhen)
00572 {
00573     // Check the Priority Queue first.
00574     //
00575     PTASK_RECORD pTask = m_PriorityHeap.PeekAtTopmost();
00576     if (pTask)
00577     {
00578         if (pTask->iPriority <= m_minPriority)
00579         {
00580             ltaWhen->SetSeconds(0);
00581             return true;
00582         }
00583     }
00584 
00585     // Check the When Queue next.
00586     //
00587     pTask = m_WhenHeap.PeekAtTopmost();
00588     if (pTask)
00589     {
00590         *ltaWhen = pTask->ltaWhen;
00591         return true;
00592     }
00593     return false;
00594 }
00595 
00596 #define HEAP_LEFT_CHILD(x) (2*(x)+1)
00597 #define HEAP_RIGHT_CHILD(x) (2*(x)+2)
00598 #define HEAP_PARENT(x) (((x)-1)/2)
00599 
00600 void CTaskHeap::SiftDown(int iSubRoot, SCHCMP *pfCompare)
00601 {
00602     int parent = iSubRoot;
00603     int child = HEAP_LEFT_CHILD(parent);
00604 
00605     PTASK_RECORD Ref = m_pHeap[parent];
00606 
00607     while (child < m_nCurrent)
00608     {
00609         int rightchild = HEAP_RIGHT_CHILD(parent);
00610         if (rightchild < m_nCurrent)
00611         {
00612             if (pfCompare(m_pHeap[rightchild], m_pHeap[child]) < 0)
00613             {
00614                 child = rightchild;
00615             }
00616         }
00617         if (pfCompare(Ref, m_pHeap[child]) <= 0)
00618             break;
00619 
00620         m_pHeap[parent] = m_pHeap[child];
00621         parent = child;
00622         child = HEAP_LEFT_CHILD(parent);
00623     }
00624     m_pHeap[parent] = Ref;
00625 }
00626 
00627 void CTaskHeap::SiftUp(int child, SCHCMP *pfCompare)
00628 {
00629     while (child)
00630     {
00631         int parent = HEAP_PARENT(child);
00632         if (pfCompare(m_pHeap[parent], m_pHeap[child]) <= 0)
00633             break;
00634 
00635         PTASK_RECORD Tmp;
00636         Tmp = m_pHeap[child];
00637         m_pHeap[child] = m_pHeap[parent];
00638         m_pHeap[parent] = Tmp;
00639 
00640         child = parent;
00641     }
00642 }
00643 
00644 PTASK_RECORD CTaskHeap::Remove(int iNode, SCHCMP *pfCompare)
00645 {
00646     if (iNode < 0 || m_nCurrent <= iNode) return NULL;
00647 
00648     PTASK_RECORD pTask = m_pHeap[iNode];
00649 
00650     m_nCurrent--;
00651     m_pHeap[iNode] = m_pHeap[m_nCurrent];
00652     SiftDown(iNode, pfCompare);
00653     SiftUp(iNode, pfCompare);
00654 
00655     return pTask;
00656 }
00657 
00658 void CTaskHeap::Update(int iNode, SCHCMP *pfCompare)
00659 {
00660     if (iNode < 0 || m_nCurrent <= iNode)
00661     {
00662         return;
00663     }
00664 
00665     SiftDown(iNode, pfCompare);
00666     SiftUp(iNode, pfCompare);
00667 }
00668 
00669 void CScheduler::TraverseUnordered(SCHLOOK *pfLook)
00670 {
00671     if (m_WhenHeap.TraverseUnordered(pfLook, CompareWhen))
00672     {
00673         m_PriorityHeap.TraverseUnordered(pfLook, ComparePriority);
00674     }
00675 }
00676 
00677 void CScheduler::TraverseOrdered(SCHLOOK *pfLook)
00678 {
00679     m_PriorityHeap.TraverseOrdered(pfLook, ComparePriority);
00680     m_WhenHeap.TraverseOrdered(pfLook, CompareWhen);
00681 }
00682 
00683 // The following guarantees that in spite of any changes to the heap
00684 // we will visit every record exactly once. It does not attempt to
00685 // visit these records in any particular order.
00686 //
00687 int CTaskHeap::TraverseUnordered(SCHLOOK *pfLook, SCHCMP *pfCompare)
00688 {
00689     // Indicate that everything has not been visited.
00690     //
00691     m_iVisitedMark++;
00692     if (m_iVisitedMark == 0)
00693     {
00694         // We rolled over. Yeah, this code will probably never run, but
00695         // let's go ahead and mark all the records as visited anyway.
00696         //
00697         for (int i = 0; i < m_nCurrent; i++)
00698         {
00699             PTASK_RECORD p = m_pHeap[i];
00700             p->m_iVisitedMark = m_iVisitedMark;
00701         }
00702         m_iVisitedMark++;
00703     }
00704 
00705     int bUnvisitedRecords;
00706     do
00707     {
00708         bUnvisitedRecords = false;
00709         for (int i = 0; i < m_nCurrent; i++)
00710         {
00711             PTASK_RECORD p = m_pHeap[i];
00712 
00713             if (p->m_iVisitedMark == m_iVisitedMark)
00714             {
00715                 // We have already seen this one.
00716                 //
00717                 continue;
00718             }
00719             bUnvisitedRecords = true;
00720             p->m_iVisitedMark = m_iVisitedMark;
00721 
00722             int cmd = pfLook(p);
00723             switch (cmd)
00724             {
00725             case IU_REMOVE_TASK:
00726                 Remove(i, pfCompare);
00727                 break;
00728 
00729             case IU_DONE:
00730                 return false;
00731 
00732             case IU_UPDATE_TASK:
00733                 Update(i, pfCompare);
00734                 break;
00735             }
00736         }
00737     } while (bUnvisitedRecords);
00738     return true;
00739 }
00740 
00741 // The following does not allow for changes during the traversal, but
00742 // but it does visit each record in sorted order (When-order or
00743 // Priority-order depending on the heap).
00744 //
00745 int CTaskHeap::TraverseOrdered(SCHLOOK *pfLook, SCHCMP *pfCompare)
00746 {
00747     Sort(pfCompare);
00748 
00749     for (int i = m_nCurrent-1; i >= 0; i--)
00750     {
00751         PTASK_RECORD p = m_pHeap[i];
00752         int cmd = pfLook(p);
00753         if (IU_DONE == cmd)
00754         {
00755             break;
00756         }
00757     }
00758 
00759     Remake(pfCompare);
00760     return true;
00761 }
00762 
00763 void CTaskHeap::Sort(SCHCMP *pfCompare)
00764 {
00765     int s_nCurrent = m_nCurrent;
00766     while (m_nCurrent--)
00767     {
00768         PTASK_RECORD p = m_pHeap[m_nCurrent];
00769         m_pHeap[m_nCurrent] = m_pHeap[0];
00770         m_pHeap[0] = p;
00771         SiftDown(0, pfCompare);
00772     }
00773     m_nCurrent = s_nCurrent;
00774 }
00775 
00776 void CTaskHeap::Remake(SCHCMP *pfCompare)
00777 {
00778     int s_nCurrent = m_nCurrent;
00779     m_nCurrent = 0;
00780     while (s_nCurrent--)
00781     {
00782         m_nCurrent++;
00783         SiftUp(m_nCurrent-1, pfCompare);
00784     }
00785 }
00786 
00787 void CScheduler::SetMinPriority(int arg_minPriority)
00788 {
00789     m_minPriority = arg_minPriority;
00790 }

Generated on Mon May 28 04:40:11 2007 for MUX by  doxygen 1.4.7