/*static char *SCCSID = "@(#)tom.c      6.6 91/06/21";*/
#define SCCSID "@(#)tom.c       6.6 91/06/21"

/*
 *      Tasking - Timeout Manager Implementation
 *
 *      IBM/Microsoft Confidential
 *
 *      Copyright (c) IBM Corporation 1987, 1989, 1991
 *      Copyright (c) Microsoft Corporation 1987, 1989, 1991
 *
 *      All Rights Reserved
 *
 *      MODIFICATION LOG
 *      ================
 *
 *      93353 - Modified code to avoid early time outs. This happens
 *              when the sum of SISData.SIS_MsCount and cmsec overflows
 *              toe_cmsec(32 bits).
 *              SISData.SIS_MsCount -> System time. => toe_mscount.
 *              cmsec -> time out parameter requested. => toe_cmsec.
 *              Replaced the following:
 *              (ptoe-> toe_cmsec) WITH (ptoe-> toe_cmsec + ptoe ->toe_mscount)
 *
 *
 */

#define INCL_TYPES
#define FNO_NUM FNO_TOM_C
#include <fnotask.h>
#include <basedef.h>
#include <basemac.h>                    // P723209
#include <osmac.h>
#include <osconst.h>
#include <ostypes.h>
#include <infoseg.h>
#include <mi.h>
#include <dossymc.h>
#include <proc.h>
#include <error.h>
#include <sigdef.h>
#include <except.h>
#include <seldesc.h>
#include <pgexport.h>
#include <vmexport.h>
#include <vmowner.h>
#include <tkexport.h>
#include <sched.h>
#include <semxport.h>
#include <kutil.h>
#include <tom.h>
#include <string.h>

#define ENABLE() _enable()
#define DISABLE() _disable()


/***LP  tomAssert - cause internal error if assertion fails
 *
 *      Given a boolean, this procedure causes an internal error if
 *      the boolean is false.  Typically, the value of this boolean is
 *      derived from some test expression.
 *
 *      tomAssert (f)
 *
 *      ENTRY   f               - boolean value (int)
 *      RETURN  NONE
 *
 *      CALLS   _assert
 *
 *      WARNING This procedure is implemented as a macro.
 *
 *      EFFECTS NONE
/ */
#ifdef  MISCSTRICT
#  define tomAssert(e) _assert(e)
#else
#  define tomAssert(e)
#endif


extern ULONG FreqSet(ULONG ulFreq);
extern  void    tomStartMigration (ulong_t itow);
extern  void    tomMigrateAll     (void);
extern struct InfoSegGDT        SISData;            /* Kernel infoseg data  */


// ****   START of PROFILE Section
// This next section is for profiling the TOM component.  The TOM_PROFILE
// constant may be defined to enable many internal checks.  These checks
// should not be enabled where performance is essential; but should be
// enabled otherwise.

#if defined (MISCSTRICT)                // building strict checking kernel...
#define TOM_PROFILE                     // ... enable profiling
#endif

#if defined (TOM_PROFILE)
#define tomProfile(c) ++(c);

ulong_t ctomTick            = 0;        // TOMTick (always post-EOI)
ulong_t ctom32hz            = 0;        // programmed clock to 32hz
ulong_t ctom128hz           = 0;        // programmed clock to 128hz
ulong_t ctomCancel          = 0;        // top of TOMCancel

ulong_t ctomSetFire         = 0;        // Set zero duration timer
ulong_t ctomSet8msRes       = 0;        // Set an 8ms resolution timer
ulong_t ctomSet32msRes      = 0;        // Set a 32ms resolution timer
ulong_t cSetOrderForever    = 0;        // Set forever timer

ulong_t ctomStartMigration  = 0;        // top of tomStartMigration
ulong_t ctomMigrateAll      = 0;        // top of tomMigrateAll
ulong_t ctomMigrate         = 0;        // one for each timer that Migrated
ulong_t ctomFire            = 0;        // Called timer's worker

                                        // Migration into hi res buckets
ulong_t cMigrateHiRes[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
ulong_t cMigrateNext8       = 0;        // Migration into pending 8ms bucket
ulong_t cMigrateNext32      = 0;        // Migration into pending 32ms bucket
ulong_t cMigrateOrder0      = 0;        // Migration into Order 0 bucket
ulong_t cMigrateOrder1      = 0;        // Migration into Order 1 bucket
ulong_t cMigrateOrder2      = 0;        // Migration into Order 2 bucket
ulong_t cMigrateOrder3      = 0;        // Migration into Order 3 bucket
ulong_t cMigrateOrder4      = 0;        // Migration into Order 4 bucket
ulong_t cMigrateOrder5      = 0;        // Migration into Order 5 bucket

ulong_t ctomFiredEarly      = 0;        // Should always be zero!!!
ulong_t ctomMaxEarly        = 0;        // Maximum time timer fired early.
ulong_t ctomMax8Late        = 0;        // Max time 8ms res timer fired late
ulong_t ctomMax32Late       = 0;        // Max time 32ms res timer fired late


// The following are some linking checks.  These help find obscure problems:
// It is unsafe to TomSet a timer which is already set.  It is unsafe
// to TomCancel a timer which is not set or already cancelled.  Kernel
// components tom, beep and tasking could potentially violate these rules.
// Let's help keep the kernel honest.  Note: these checks do not detect ALL
// illegal conditions.

// This is useful for verifying linking operations on time out elements.
// If prev == next, they must point to the hash buckets.
// Do NOT use this on FOREVER timers (prev == next but not in hash buckets)
#define tomAssertLinkedToe(ptoe)                                             \
  tomAssert(                                                                 \
       (ptoe-> toe_ptoePrev != ptoe-> toe_ptoeNext) ||                       \
       ( (ptoe-> toe_ptoePrev  >= (toe_t *) &atowHash[TOM_HASHBASE])   &&    \
         (ptoe-> toe_ptoePrev  <= (toe_t *) &atowHash[TOM_LAST_HASHBASE])    \
       )                                                                     \
  );


// This is useful for verifying linking operations on the hash buckets.
// If next == prev, they can point anywhere (to self or single toe);
// If next != prev, they must point outside the hash buckets.
#define tomAssertLinkedItow(itow)                                       \
  tomAssert(                                                            \
    (atowHash[itow].tow_ptoePrev == atowHash[itow].tow_ptoeNext) ||     \
    (                                                                   \
      (                                                                 \
        ((ulong_t)atowHash[itow].tow_ptoePrev <                         \
         (ulong_t)&atowHash[TOM_HASHBASE]) ||                           \
        ((ulong_t)atowHash[itow].tow_ptoePrev >                         \
         (ulong_t)&atowHash[TOM_LAST_HASHBASE])                         \
      ) &&                                                              \
      (                                                                 \
        ((ulong_t)atowHash[itow].tow_ptoeNext <                         \
        (ulong_t)&atowHash[TOM_HASHBASE]) ||                            \
        ((ulong_t)atowHash[itow].tow_ptoeNext >                         \
        (ulong_t)&atowHash[TOM_LAST_HASHBASE])                          \
      )                                                                 \
    )                                                                   \
  );


// This is useful for monitoring if timers fired early or fired too late.
void tomCheckFire(toe_t *ptoe) {

ULONG mscount;                            //elapsed time - 93353

    if (SISData.SIS_MsCount < ptoe->toe_mscount)                            //93353
        mscount = 0xffffffff - ptoe->toe_mscount + SISData.SIS_MsCount + 1; //93353
    else                                                                    //93353
        mscount = SISData.SIS_MsCount - ptoe->toe_mscount;                  //93353

    if (!(mscount >= ptoe-> toe_cmsec)) {
        tomProfile(ctomFiredEarly);
        if (ctomMaxEarly < (ptoe-> toe_cmsec - mscount)) {
            ctomMaxEarly = (ptoe-> toe_cmsec - mscount);
        }
    } else {
        if (ptoe-> toe_worker & TOM_HIRES_FLAG) {
            if (ctomMax8Late < (mscount - ptoe-> toe_cmsec)) {
                ctomMax8Late = (mscount - ptoe-> toe_cmsec);
            }
        } else {
            if (ctomMax32Late < (mscount - ptoe-> toe_cmsec)) {
                ctomMax32Late = (mscount - ptoe-> toe_cmsec);
            }
        }
    }

    // TomTime should never exceed System Time.
    tomAssert(cmsecTomTime <= SISData.SIS_MsCount);

    // Timers should never fire early.
    tomAssert(mscount >= ptoe-> toe_cmsec);
}

#else
#define tomProfile(c)
#define tomAssertLinkedToe(ptoe)
#define tomAssertLinkedItow(itow)
#endif
// **** END of PROFILE Section


/***    TOMapfn - Tom Worker array.
 *
 *      TOMapfn is an array of worker routine addresses, which are called
 *      if the timeout fires.  The index of the array is given by
 *      ptoe->toe_ipfnTom.
 *
 *      To add a new function, define a new TOM_W_... value, then just
 *      add a new element to this array at that index.
 *
 *      TKTomWake       - TKSleep Timeout Expired
 *      TKTomStarve     - Apply Starvation Boost to a thread
 *      TIMTomClear     - Clear a timer-services semaphore
 *      BeepTom         - Turn off the speaker
 *      VDMMTomHook     - Call an VDMM timer-controlled Hook
 *      TKTomTimeslice  - Check for a scheduler timeslice
 *
 */

void    (*(TOMapfn[TOM_W_MAX])) (toe_t *ptoe) = {
        TKTomWake,                      // TOM_W_WAKE
        TKTomStarve,                    // TOM_W_STARVE
        TIMTomClear,                    // TOM_W_TIMCLEAR
        BeepTom,                        // TOM_W_BEEPDONE
        VDMMTomHook,                    // TOM_W_VDMMHOOK
        TKTomTimeslice,                 // TOM_W_TIMESLICE
        SMTomHook,                      // TOM_W_SWAPSHRINK
        FSTomCodeUnlock,                // TOM_W_CODEUNLOCK
#ifdef TOMTESTWORKER
        tomTestWorker                   // TOM_W_TEST
#endif
};

ulong_t  cmsecTomTime = 0;              // Time according to lo res timers
ulong_t  cmsecHiResTomTime;             // Time according to hi res timers
ulong_t  tomHiResPending = 0;           // Bit flags of pending hi res timers


/***LD  Timeout Manager Hashed-Heirarchical Timing Wheels
 *      There are 109 timing wheels, each having two pointers.
 *      Each wheel is circularly linked through a head in the hash table.
 */

tow_t   atowHash[TOM_HASHSIZE] = {

        // High Resolution Timer Hash Base.  One wheel per 8ms, 16 times,
        // One tick = 7.8125ms.  These buckets have to be within first
        // 32 buckets of atowHash.  Put them first.

        { (toe_t *) &atowHash[ 0], (toe_t *) &atowHash[ 0] },
        { (toe_t *) &atowHash[ 1], (toe_t *) &atowHash[ 1] },
        { (toe_t *) &atowHash[ 2], (toe_t *) &atowHash[ 2] },
        { (toe_t *) &atowHash[ 3], (toe_t *) &atowHash[ 3] },
        { (toe_t *) &atowHash[ 4], (toe_t *) &atowHash[ 4] },
        { (toe_t *) &atowHash[ 5], (toe_t *) &atowHash[ 5] },
        { (toe_t *) &atowHash[ 6], (toe_t *) &atowHash[ 6] },
        { (toe_t *) &atowHash[ 7], (toe_t *) &atowHash[ 7] },
        { (toe_t *) &atowHash[ 8], (toe_t *) &atowHash[ 8] },
        { (toe_t *) &atowHash[ 9], (toe_t *) &atowHash[ 9] },
        { (toe_t *) &atowHash[10], (toe_t *) &atowHash[10] },
        { (toe_t *) &atowHash[11], (toe_t *) &atowHash[11] },
        { (toe_t *) &atowHash[12], (toe_t *) &atowHash[12] },
        { (toe_t *) &atowHash[13], (toe_t *) &atowHash[13] },
        { (toe_t *) &atowHash[14], (toe_t *) &atowHash[14] },
        { (toe_t *) &atowHash[15], (toe_t *) &atowHash[15] },

        // Next8 Base.  One wheel for timers which will fire the next
        // 8ms resolution tick.  This bucket has to be within first
        // 32 buckets of atowHash.  Put it here.

        { (toe_t *) &atowHash[16], (toe_t *) &atowHash[16] },

        // Next32 Base.  One wheel for timers which will fire the next
        // 32ms resolution tick.

        { (toe_t *) &atowHash[17], (toe_t *) &atowHash[17] },

        // Order 0 Hash Base.  One wheel per tick, 32 times.
        // One Tick = 31.25ms

        { (toe_t *) &atowHash[18], (toe_t *) &atowHash[18] },
        { (toe_t *) &atowHash[19], (toe_t *) &atowHash[19] },
        { (toe_t *) &atowHash[20], (toe_t *) &atowHash[20] },
        { (toe_t *) &atowHash[21], (toe_t *) &atowHash[21] },
        { (toe_t *) &atowHash[22], (toe_t *) &atowHash[22] },
        { (toe_t *) &atowHash[23], (toe_t *) &atowHash[23] },
        { (toe_t *) &atowHash[24], (toe_t *) &atowHash[24] },
        { (toe_t *) &atowHash[25], (toe_t *) &atowHash[25] },
        { (toe_t *) &atowHash[26], (toe_t *) &atowHash[26] },
        { (toe_t *) &atowHash[27], (toe_t *) &atowHash[27] },
        { (toe_t *) &atowHash[28], (toe_t *) &atowHash[28] },
        { (toe_t *) &atowHash[29], (toe_t *) &atowHash[29] },
        { (toe_t *) &atowHash[30], (toe_t *) &atowHash[30] },
        { (toe_t *) &atowHash[31], (toe_t *) &atowHash[31] },
        { (toe_t *) &atowHash[32], (toe_t *) &atowHash[32] },
        { (toe_t *) &atowHash[33], (toe_t *) &atowHash[33] },
        { (toe_t *) &atowHash[34], (toe_t *) &atowHash[34] },
        { (toe_t *) &atowHash[35], (toe_t *) &atowHash[35] },
        { (toe_t *) &atowHash[36], (toe_t *) &atowHash[36] },
        { (toe_t *) &atowHash[37], (toe_t *) &atowHash[37] },
        { (toe_t *) &atowHash[38], (toe_t *) &atowHash[38] },
        { (toe_t *) &atowHash[39], (toe_t *) &atowHash[39] },
        { (toe_t *) &atowHash[40], (toe_t *) &atowHash[40] },
        { (toe_t *) &atowHash[41], (toe_t *) &atowHash[41] },
        { (toe_t *) &atowHash[42], (toe_t *) &atowHash[42] },
        { (toe_t *) &atowHash[43], (toe_t *) &atowHash[43] },
        { (toe_t *) &atowHash[44], (toe_t *) &atowHash[44] },
        { (toe_t *) &atowHash[45], (toe_t *) &atowHash[45] },
        { (toe_t *) &atowHash[46], (toe_t *) &atowHash[46] },
        { (toe_t *) &atowHash[47], (toe_t *) &atowHash[47] },
        { (toe_t *) &atowHash[48], (toe_t *) &atowHash[48] },
        { (toe_t *) &atowHash[49], (toe_t *) &atowHash[49] },

        // Order 1 Hash Base.  One wheel 1K msec, 32 times.
        // 1K msec is about 1 Second.

        { (toe_t *) &atowHash[50], (toe_t *) &atowHash[50] },
        { (toe_t *) &atowHash[51], (toe_t *) &atowHash[51] },
        { (toe_t *) &atowHash[52], (toe_t *) &atowHash[52] },
        { (toe_t *) &atowHash[53], (toe_t *) &atowHash[53] },
        { (toe_t *) &atowHash[54], (toe_t *) &atowHash[54] },
        { (toe_t *) &atowHash[55], (toe_t *) &atowHash[55] },
        { (toe_t *) &atowHash[56], (toe_t *) &atowHash[56] },
        { (toe_t *) &atowHash[57], (toe_t *) &atowHash[57] },
        { (toe_t *) &atowHash[58], (toe_t *) &atowHash[58] },
        { (toe_t *) &atowHash[59], (toe_t *) &atowHash[59] },
        { (toe_t *) &atowHash[60], (toe_t *) &atowHash[60] },
        { (toe_t *) &atowHash[61], (toe_t *) &atowHash[61] },
        { (toe_t *) &atowHash[62], (toe_t *) &atowHash[62] },
        { (toe_t *) &atowHash[63], (toe_t *) &atowHash[63] },
        { (toe_t *) &atowHash[64], (toe_t *) &atowHash[64] },
        { (toe_t *) &atowHash[65], (toe_t *) &atowHash[65] },
        { (toe_t *) &atowHash[66], (toe_t *) &atowHash[66] },
        { (toe_t *) &atowHash[67], (toe_t *) &atowHash[67] },
        { (toe_t *) &atowHash[68], (toe_t *) &atowHash[68] },
        { (toe_t *) &atowHash[69], (toe_t *) &atowHash[69] },
        { (toe_t *) &atowHash[70], (toe_t *) &atowHash[70] },
        { (toe_t *) &atowHash[71], (toe_t *) &atowHash[71] },
        { (toe_t *) &atowHash[72], (toe_t *) &atowHash[72] },
        { (toe_t *) &atowHash[73], (toe_t *) &atowHash[73] },
        { (toe_t *) &atowHash[74], (toe_t *) &atowHash[74] },
        { (toe_t *) &atowHash[75], (toe_t *) &atowHash[75] },
        { (toe_t *) &atowHash[76], (toe_t *) &atowHash[76] },
        { (toe_t *) &atowHash[77], (toe_t *) &atowHash[77] },
        { (toe_t *) &atowHash[78], (toe_t *) &atowHash[78] },
        { (toe_t *) &atowHash[79], (toe_t *) &atowHash[79] },
        { (toe_t *) &atowHash[80], (toe_t *) &atowHash[80] },
        { (toe_t *) &atowHash[81], (toe_t *) &atowHash[81] },

        // Order 2 Hash Base.  One wheel per 32K msec, 16 times.
        // 32K msec is about 1/2 minute.

        { (toe_t *) &atowHash[82], (toe_t *) &atowHash[82] },
        { (toe_t *) &atowHash[83], (toe_t *) &atowHash[83] },
        { (toe_t *) &atowHash[84], (toe_t *) &atowHash[84] },
        { (toe_t *) &atowHash[85], (toe_t *) &atowHash[85] },
        { (toe_t *) &atowHash[86], (toe_t *) &atowHash[86] },
        { (toe_t *) &atowHash[87], (toe_t *) &atowHash[87] },
        { (toe_t *) &atowHash[88], (toe_t *) &atowHash[88] },
        { (toe_t *) &atowHash[89], (toe_t *) &atowHash[89] },
        { (toe_t *) &atowHash[90], (toe_t *) &atowHash[90] },
        { (toe_t *) &atowHash[91], (toe_t *) &atowHash[91] },
        { (toe_t *) &atowHash[92], (toe_t *) &atowHash[92] },
        { (toe_t *) &atowHash[93], (toe_t *) &atowHash[93] },
        { (toe_t *) &atowHash[94], (toe_t *) &atowHash[94] },
        { (toe_t *) &atowHash[95], (toe_t *) &atowHash[95] },
        { (toe_t *) &atowHash[96], (toe_t *) &atowHash[96] },
        { (toe_t *) &atowHash[97], (toe_t *) &atowHash[97] },

        // Order 3 Hash Base.  One wheel per 512K msec, 8 times.
        // 512K msec is about 8 minutes.

        { (toe_t *) &atowHash[98], (toe_t *) &atowHash[98] },
        { (toe_t *) &atowHash[99], (toe_t *) &atowHash[99] },
        { (toe_t *) &atowHash[100], (toe_t *) &atowHash[100] },
        { (toe_t *) &atowHash[101], (toe_t *) &atowHash[101] },
        { (toe_t *) &atowHash[102], (toe_t *) &atowHash[102] },
        { (toe_t *) &atowHash[103], (toe_t *) &atowHash[103] },
        { (toe_t *) &atowHash[104], (toe_t *) &atowHash[104] },
        { (toe_t *) &atowHash[105], (toe_t *) &atowHash[105] },

        // Order 4 Hash Base.  One wheel traversed every 4M msec.
        // 4M msec is about 1 hour.  4M msec to 128M msec timers collide.

        { (toe_t *) &atowHash[106], (toe_t *) &atowHash[106] },

        // Order 5 Hash Base.  One wheel traversed every 128M msec.
        // 128M msec is about 1.5 days.  128M msec to 4G msec timers collide.

        { (toe_t *) &atowHash[107], (toe_t *) &atowHash[107] },

        // Migration Base.  Used by TOMTick for Migration

        { (toe_t *) &atowHash[108], (toe_t *) &atowHash[108] }

};

/***    Pre-initialized TOM Events
 *
 *      toeTimeslice - Timeslice TOM event
 */

toe_t   toeTimeslice = {&toeTimeslice, &toeTimeslice, -1, 0};

int TOMQuery(toe_t *ptoe)                          // P723209
{                                                  // P723209
   int rc;                                         // P723209
   rc = TRUE;                                      // P723209
   if ((ptoe-> toe_ptoeNext == ptoe) &&            // P723209
       (ptoe-> toe_ptoePrev == ptoe)){             // P723209
       rc = FALSE;                                 // P723209
   }                                               // P723209
   return(rc);                                     // P723209
}                                                  // P723209

/***EP  TOMSet - Set a timed event to fire soon
 *
 *      The toe_t struture is usually embedded within another structure.
 *
 *      The toe must not already be set, except if the previous TOMSet
 *      call specified an infinite (-1) timeout.  An infinite timeout
 *      can be used to allow cancelling a timer multiple times.
 *
 *      ENTRY   ptoe     - pointer to toe_t structure to use.
 *              cmsec    - number of miliseconds (from now) to wait.
 *              iapfnTom - high resolution timer flag and index
 *                         to worker function.  See TOM_W_ definition.
 *
 *      EXIT    void
 *
 */

void
TOMSet (toe_t *ptoe,                // pointer to toe to use
    ulong_t cmsec,                  // number of milliseconds to wait
    ulong_t iapfnTom)               // hires-flag | index to worker function
{
    ulong_t procflags;              // process flags from TKDisable
    ulong_t itow;                   // Timeout Wheel Index

    // Nothing besides worker and hi res flag should be in function word
    tomAssert (!(iapfnTom & ~(TOM_HIRES_FLAG | TOM_WORKER_MASK)));

#if defined (TOM_PROFILE)
    if (iapfnTom & TOM_HIRES_FLAG) {
        tomProfile(ctomSet8msRes);
    } else {
        tomProfile(ctomSet32msRes);
    }
#endif

    procflags = TKDisable();

    // Save hi/lo res flag and worker index number with time out element
    ptoe-> toe_worker = (toe_worker_t) iapfnTom;

    // Save destination time with time out element
    // Note that REAL-TIME is actually 0-31.25ms (if RTC Frequency == 32hz)
    // or 0-7.8125ms (if RTC Frequency == 128hz) MORE THAN the current
    // value of SIS_MsCount.  Therefore, timers will generally go off
    // earlier than requested in REAL-TIME.  Since OS/2 does not know what
    // the REAL-TIME is, it uses system time, which is the best it can do.
    // A timer will never go off earlier than requested in system time.

    ptoe-> toe_cmsec   = cmsec;                //Time out parameter - 93353
    ptoe-> toe_mscount = SISData.SIS_MsCount;  //System time - 93353

    // Compute the index to the proper hash table bucket that this timer
    // should be appended to, based on its destination time.

    if (cmsec == TOM_WAIT_FOREVER) {

        // Wait forever has been selected; place it in it's own empty list.

        ptoe-> toe_ptoeNext = ptoe;
        ptoe-> toe_ptoePrev = ptoe;
        tomProfile(cSetOrderForever);

    } else if (cmsec == 0) {

        // A zero duration timer was passed; cancel and fire it immediately

        ptoe-> toe_ptoeNext = ptoe;
        ptoe-> toe_ptoePrev = ptoe;
        ENABLE();
        // TomSet, TomCancel can occur here.
        TOMapfn[ptoe->toe_worker & TOM_WORKER_MASK] (ptoe);
        DISABLE();
        tomProfile(ctomFire);

    } else {  // Everything else must be linked into hash buckets.

        if ((!(iapfnTom & TOM_HIRES_FLAG)) ||
            (cmsec >= TOM_HIRES_HASHTIME)) {

            // All normal timers, and any hi resolution timers that are at
            // least 128ms away get inserted into the 32ms resolution hash
            // buckets.

            if (cmsec & TOM_ORDER0_LIMIT_MASK) {
                if (cmsec & TOM_ORDER1_LIMIT_MASK) {
                    if (cmsec & TOM_ORDER2_LIMIT_MASK) {
                        if (cmsec & TOM_ORDER3_LIMIT_MASK) {
                            if (cmsec & TOM_ORDER4_LIMIT_MASK) {
                                    tomProfile(cMigrateOrder5);
                                    itow = TOM_ORDER5_HASHBASE;
                            } else {
                                tomProfile(cMigrateOrder4);
                                itow = TOM_ORDER4_HASHBASE;
                            }
                        } else {
                            tomProfile(cMigrateOrder3);
                            itow = TOM_ORDER3_HASHBASE +
                              (((ptoe-> toe_cmsec + ptoe->toe_mscount) &
                                                    TOM_ORDER3_MASK) >>
                                                   TOM_ORDER3_SHIFT);
                        }
                    } else {
                        tomProfile(cMigrateOrder2);
                        itow = TOM_ORDER2_HASHBASE +
                          (((ptoe-> toe_cmsec + ptoe->toe_mscount) &
                                                TOM_ORDER2_MASK) >>
                                               TOM_ORDER2_SHIFT);
                    }
                } else {
                    tomProfile(cMigrateOrder1);
                    itow = TOM_ORDER1_HASHBASE +
                      (((ptoe-> toe_cmsec + ptoe->toe_mscount) &
                                             TOM_ORDER1_MASK) >>
                                           TOM_ORDER1_SHIFT);
                }
            } else {
                tomProfile(cMigrateOrder0);
                itow = TOM_ORDER0_HASHBASE +
                  (((ptoe-> toe_cmsec + ptoe->toe_mscount) &
                                        TOM_ORDER0_MASK) >>
                                       TOM_ORDER0_SHIFT);
            }

        } else {

            // Hi resolution timers 1-127ms in duration

            // If the clock frequency is 32hz, hi res timers with less than
            // 32ms don't permit enough lead time to reprogram the clock to
            // 128hz and insure hi resolution.  However, if the clock
            // frequency is already fast, the timer can be fired with hi
            // resolution.  Periodic hi res timers of a duration less than
            // 128ms will keep getting reinserted into the hi res buckets
            // and keep the clock rate fast.   The first period of a hi res
            // periodic timer may exceed hi resolution limits, but
            // subsequent firings of the periodic hi res timer will be
            // within hi res limits.

            itow = TOM_HIRES_HASHBASE +
               (((ptoe-> toe_cmsec + ptoe->toe_mscount) & TOM_HIRES_MASK) >>
                                    TOM_HIRES_SHIFT);

            if (!tomHiResPending) {
                cmsecHiResTomTime = SISData.SIS_MsCount;
                FreqSet(128);
                tomProfile(ctom128hz)
            }

            tomProfile(cMigrateHiRes[itow]);
            tomHiResPending |= (1 << itow);
        }

        // Insert the toe at the tail of that list.  We use the
        // tail to get round-robin effects.

        ptoe-> toe_ptoePrev = atowHash[itow].tow_ptoePrev;
        ptoe-> toe_ptoeNext = (toe_t *) &(atowHash + itow);
        atowHash[itow].tow_ptoePrev-> toe_ptoeNext = ptoe;
        atowHash[itow].tow_ptoePrev = ptoe;

        tomAssertLinkedToe(ptoe);
        tomAssertLinkedItow(itow);
    }

    TKEnable(procflags);
}


/***EP  TOMCancel - Cancel a timed event
 *
 *      TOMCancel cancels any timeout at any point in the TOM structure.
 *
 *      The timer must have already been initialized at this time,
 *      or undefined events may occur.  Initialization can be accomplished
 *      by assuring that any timer that is cancelled has already been set
 *      at least once before calling TOMCancel.  Cancelling a timer
 *      multiple times is allowed.  Cancelling a timer that has been fired
 *      is allowed.
 *
 *      If it is not practical to set a timer at the moment that the
 *      timer is initialized, calling TOMSet with an infinite timeout
 *      will be sufficient to initialize the timer.
 *
 *      If the timer being cancelled is a high resolution timer, and
 *      no other hi res timer is expected to fire within 64ms, we could slow
 *      the clock down as part of the cancel.  However, tomCancel is called
 *      often, and few hi res timers within 64ms get cancelled.  So
 *      hi res timers are just unlinked; TomTick will "fire" a possibly
 *      empty hi res bucket and slow the clock later.
 *
 *      ENTRY   ptoe - pointer to toe_t structure to cancel.
 *
 *      EXIT    void
 *
 */

void
TOMCancel (toe_t *ptoe)                 // pointer to toe to cancel
{
        ulong_t procflags;              // process flags from TKDisable

        procflags = TKDisable();

        // For profiling the TOM component.
        tomProfile(ctomCancel);

        // Some sanity checks... is it safe to cancel this?
        tomAssert (                             \
          (ptoe != NULL) &&                     \
          (ptoe-> toe_ptoeNext != NULL) &&      \
          (ptoe-> toe_ptoePrev != NULL)         \
        );

        // If prev != next, ptoe is (should be) set with others...
        // (next, prev can point anywhere);
        // If prev == next,  ptoe is cancelled (points to self) or
        // ptoe is set by self (points to same hash bucket)
        // Otherwise, it is unsafe to mess with ptoe.
        tomAssert(                                                           \
          (ptoe-> toe_ptoePrev != ptoe-> toe_ptoeNext) ||                    \
          (ptoe == ptoe-> toe_ptoePrev) ||                                   \
          (                                                                  \
            (ptoe-> toe_ptoePrev  >= (toe_t *) &atowHash[TOM_HASHBASE])   && \
            (ptoe-> toe_ptoePrev  <= (toe_t *) &atowHash[TOM_LAST_HASHBASE]) \
          )                                                                  \
        );

        ptoe-> toe_ptoeNext-> toe_ptoePrev = ptoe-> toe_ptoePrev;
        ptoe-> toe_ptoePrev-> toe_ptoeNext = ptoe-> toe_ptoeNext;
        ptoe-> toe_ptoeNext = ptoe;     // Allow multiple cancels.
        ptoe-> toe_ptoePrev = ptoe;
        TKEnable(procflags);
}


/***EP  TOMTick - Perform TOM Timer Tick processing
 *
 *      Perform TOM timer tick processing.
 *
 *      ENTRY   cmsec   - time, since last tick, in msec.  (unused)
 *              fPostEOI - Pre/Post-EOI indicator flag.
 *              interrupts enabled
 *
 *      EXIT    void
 *
 *      NOTE    The purpose of TOMTick is to gather all timers which must
 *              migrate this tick.  tomMigrateAll is then called to
 *              redistribute the timers that TOMTick has identified.
 *              These timers will either be reinserted onto the hash tables
 *              or fired (if their time has come or passed.)
 *
 *              We use the system's running millisecond counter SIS_MsCount
 *              as our time base.  This keeps timers synchronous with the
 *              time of day.  (Assuming that SIS_MsCount is synchronous
 *              with the time of day.)
 *
 */

void
TOMTick (ulong_t cmsec,                 // time since last tick
         ulong_t fPostEOI)              // Pre or Post-EOI indicator flag
{
    ulong_t procflags;                  // process flags from TKDisable
    ulong_t itow;

    if (!fPostEOI) {  // Pre-EOI
        // BUGBUG -- nothing to do; change SchedClock not to call
        // TOMTick if pre-EOI
        return;
    }

    procflags = TKDisable();

    // For profiling the TOM component.
    tomProfile(ctomTick);

    // The check for hi res timers pending should be fast.  We use bits in
    // tomHiResPending to indicate non-empty hi res buckets that need to be
    // fired.  It is important that tomHiResPending accurately reflects the
    // status of the hi res buckets.

    if (tomHiResPending) {

        // Migrate any hi res timers that had 1-7ms to go last time.
        // This will fire this tick.

        if (atowHash[TOM_NEXT8_HASHBASE].tow_ptoeNext !=
            (toe_t *) &atowHash[TOM_NEXT8_HASHBASE]) {
            tomHiResPending &= (~(1 << TOM_NEXT8_HASHBASE));
            tomStartMigration(TOM_NEXT8_HASHBASE);
        }

        // Scan through hi res timer buckets whose time has come.  Bring
        // HiResTomTime up to SystemTime.

        do {

            // Migrate all hi res buckets whose time falls within the
            // period of time that has just transpired.

            itow = TOM_HIRES_HASHBASE +
                     ((cmsecHiResTomTime & TOM_HIRES_MASK) >>
                                           TOM_HIRES_SHIFT);

            if (tomHiResPending & (1 << itow)) {
                tomHiResPending &= (~(1 << itow));
                tomStartMigration(itow);
            }

            // There are at most 16 hi res buckets that will migrate during
            // this loop.  We may not be able to do all 16 within interrupt
            // latency limits, so give others a chance.

            ENABLE();
            TKBitBucket = 0;        // Interrupts can occur here.
            DISABLE();

            // Keep incrementing HiResTime until it catches up to
            // SystemTime, but insure the endpoint condition (HiResTomTime
            // == SystemTime) is processed.

            if (cmsecHiResTomTime < SISData.SIS_MsCount) {
                cmsecHiResTomTime += TOM_8MS_TICK; // hi res bucket width is 8ms
                if (cmsecHiResTomTime > SISData.SIS_MsCount) {
                    cmsecHiResTomTime = SISData.SIS_MsCount;
                }
            } else { // (cmsecHiResTomTime == SISData.SIS_MsCount)
                cmsecHiResTomTime++;  // force loop exit
            }
        } while (tomHiResPending && (cmsecHiResTomTime <= SISData.SIS_MsCount));

        cmsecHiResTomTime--;  // correction from forced loop exit above

        if (!tomHiResPending) {

            // If no hi res timers remain (within 127ms), slow the clock
            FreqSet(32);
            tomProfile(ctom32hz)
        }
    }

    if ((SISData.SIS_MsCount - cmsecTomTime) >= 31) {

        // It has been at least 31ms since we migrated normal
        // resolution timers.  Time has advanced into new normal resolution
        // bucket(s).  Perform 32ms granularity migration.

        // Fire normal resolution timers that had 1-31ms to go last tick.
        // This will fire this tick.

        if (atowHash[TOM_NEXT32_HASHBASE].tow_ptoeNext !=
            (toe_t *) &atowHash[TOM_NEXT32_HASHBASE]) {
            tomStartMigration(TOM_NEXT32_HASHBASE);
        }

        // TomTime sweeps through time in parallel with (and slightly
        // behind) SystemTime.  As TomTime catches up with with SystemTime,
        // Tom must examine all buckets within the time segment that passed.
        // Typically, SystemTime increments by 31 or 32ms. In heavy system
        // activity, tom may see SystemTime jerk forward by a larger
        // amount.  In this case, tom must sweep through time "by itself"
        // carefully not to miss buckets.

        // SIS_MsCount may advance asynchronously in the middle of this
        // do loop in those places where interrupts are enabled.  That
        // is ok -- it just keeps the loop going until TomTime is really
        // caught up with SystemTime.

        do  {

            // Start migration. We need to start migration on the
            // highest order timers first, as they have been waiting
            // the longest, for FIFO. However, we need to test the
            // lowest order timers first for speed.

            if (!(cmsecTomTime & TOM_ORDER0_MASK)) {
              if (!(cmsecTomTime & TOM_ORDER1_MASK)) {
                if (!(cmsecTomTime & TOM_ORDER2_MASK)) {
                  if (!(cmsecTomTime & TOM_ORDER3_MASK)) {
                    if (!(cmsecTomTime & TOM_ORDER4_MASK)) {
                      tomStartMigration(TOM_ORDER5_HASHBASE);
                    }
                    tomStartMigration(TOM_ORDER4_HASHBASE);
                  }
                  tomStartMigration(TOM_ORDER3_HASHBASE +
                   ((cmsecTomTime & TOM_ORDER3_MASK) >> TOM_ORDER3_SHIFT));
                }
                tomStartMigration(TOM_ORDER2_HASHBASE +
                 ((cmsecTomTime & TOM_ORDER2_MASK) >> TOM_ORDER2_SHIFT));
              }
              tomStartMigration(TOM_ORDER1_HASHBASE +
               ((cmsecTomTime & TOM_ORDER1_MASK) >> TOM_ORDER1_SHIFT));
            }

            // ORDER0 timers migrate every tick.

            tomStartMigration(TOM_ORDER0_HASHBASE +
                              ((cmsecTomTime & TOM_ORDER0_MASK)
                                            >> TOM_ORDER0_SHIFT));

            // If TomTime has fallen far behind SystemTime, this loop could
            // get a little long.  Let others come in here.

            ENABLE();
            TKBitBucket = 0;        // Interrupts can occur here.
            DISABLE();

            // Keep incrementing TomTime until it catches up to
            // SystemTime, but insure the endpoint condition (TomTime
            // == SystemTime) is processed.

            if (cmsecTomTime < SISData.SIS_MsCount) {
                cmsecTomTime += TOM_32MS_TICK; // regular bucket width is 32ms
                if (cmsecTomTime > SISData.SIS_MsCount) {
                    cmsecTomTime = SISData.SIS_MsCount;
                }
            } else { // (cmsecTomTime == SISData.SIS_MsCount)
                cmsecTomTime++;  // force loop exit
            }
        } while (cmsecTomTime <= SISData.SIS_MsCount);


        // The clock can only be sped up on 32ms boundaries.  The next
        // chance we have to speed the clock is the next 32ms tick.
        // At that time, the clock can be set to 128hz so it will be fast
        // for those hi res timers 32-64ms from now.  Looking at timers
        // 32-64ms from now usually entails examining two buckets.  This
        // is costly.  Looking 64ms ahead alone is better, but in that
        // case we will look at timers anywhere from 33-64ms to 64-95ms
        // from now.  We migrate all hi res timers within that range.

        // Hi res timers will be migrated into the hi res buckets.  Non-
        // hi res timers will just be put back where they were.  This is
        // a little redundant, but ANY timer could be a hi res timer
        // and it has to be identified by at least 64ms ahead in order
        // reprogram the clock in time.  An optimization exercise would
        // be to find hi res timers 64ms hence without unlinking and
        // relinking all the non-hi res timers.

        // Look ahead 64ms for hi res timers.
        cmsecTomTime = SISData.SIS_MsCount + (2 * TOM_32MS_TICK);

        if (!(cmsecTomTime & TOM_ORDER0_MASK)) {
          if (!(cmsecTomTime & TOM_ORDER1_MASK)) {
            if (!(cmsecTomTime & TOM_ORDER2_MASK)) {
              if (!(cmsecTomTime & TOM_ORDER3_MASK)) {
                if (!(cmsecTomTime & TOM_ORDER4_MASK)) {
                  tomStartMigration(TOM_ORDER5_HASHBASE);
                }
                tomStartMigration(TOM_ORDER4_HASHBASE);
              }
              tomStartMigration(TOM_ORDER3_HASHBASE +
               ((cmsecTomTime & TOM_ORDER3_MASK) >> TOM_ORDER3_SHIFT));
            }
            tomStartMigration(TOM_ORDER2_HASHBASE +
             ((cmsecTomTime & TOM_ORDER2_MASK) >> TOM_ORDER2_SHIFT));
          }
          tomStartMigration(TOM_ORDER1_HASHBASE +
           ((cmsecTomTime & TOM_ORDER1_MASK) >> TOM_ORDER1_SHIFT));
        }

        tomStartMigration(TOM_ORDER0_HASHBASE +
                          ((cmsecTomTime & TOM_ORDER0_MASK)
                                        >> TOM_ORDER0_SHIFT));

        cmsecTomTime = SISData.SIS_MsCount;  // Put this back for next time
    }

    // Redistribute all timers undergoing migration.  Those whose time
    // has not come yet will be reinserted into the proper hash table.
    // Those whose time has come (or passed) will be fired.

    tomMigrateAll();

    ENABLE();
}



/***EP  tomStartMigration - Prepare to Migrate Timers to a Lower Order
 *
 *      tomStartMigration takes a timing wheel index to migrate.
 *
 *      tomStartMigration will link the contents of the migrating
 *      hash bucket onto the tail of the MIGRATE bucket.
 *      tomStartMigration is called in the order 5, 4, 3, 2, 1, 0, to
 *      apporoximate FIFO ordering of the migrating events.
 *      Due to the dynamic nature of setting, cancelling and firing timers
 *      and the abscence of any sorting, FIFO order is not guaranteed.
 *
 *      tomMigrateAll must be called afterwards to finish up migration
 *      processing.
 *
 *      ENTRY   itow   - Timing Wheel index (hash bucket) to migrate from
 *              INTERRUPTS DISABLED
 *
 *      EXIT    void
 *
 *      EFFECTS
 *              Empties the itow hash bucket.
 *              Alters the TOM_MIGRATE_HASHBASE hash bucket.
 */

void
tomStartMigration (ulong_t itow)
{
        toe_t  *ptoeTmp;

        tomProfile(ctomStartMigration);

        // If nothing migrates, just leave.

        if ((ptoeTmp = atowHash[itow].tow_ptoeNext) ==
            (toe_t *) &atowHash[itow]) {
                return;
        }

        atowHash[itow].tow_ptoePrev-> toe_ptoeNext =
                (toe_t *) &atowHash[TOM_MIGRATE_HASHBASE];

        ptoeTmp-> toe_ptoePrev =
            atowHash[TOM_MIGRATE_HASHBASE].tow_ptoePrev;

        atowHash[TOM_MIGRATE_HASHBASE].tow_ptoePrev-> toe_ptoeNext =
                atowHash[itow].tow_ptoeNext;

        atowHash[TOM_MIGRATE_HASHBASE].tow_ptoePrev =
                atowHash[itow].tow_ptoePrev;

        atowHash[itow].tow_ptoeNext = (toe_t *) &atowHash[itow];

        atowHash[itow].tow_ptoePrev = (toe_t *) &atowHash[itow];

        tomAssertLinkedToe(ptoeTmp);
        tomAssertLinkedItow(itow);
        tomAssertLinkedItow(TOM_MIGRATE_HASHBASE);
}


/***EP  tomMigrateAll - Finish Migration work.
 *
 *      tomMigrateAll must be called after the last tomStartMigration call
 *      to finish up toe migration processing.
 *
 *      tomMigrateAll enables interrupts between migrating each timer.
 *      This prevents interrupt dispatch latency problems.
 *
 *      tomMigrateAll processes the events held in the MIGRATE bucket
 *      in reverse order.  For each toe on this list, tomMigrateAll
 *      selects the hash bucket to use, and places the toe at the head
 *      of that hash bucket.   This combination approximates (but does
 *      not guarantee) FIFO ordering of events with minimal overhead.
 *
 *      ENTRY   void
 *              INTERRUPTS DISABLED
 *
 *      EXIT    void
 *              INTERRUPTS DISABLED     (but allows interrupts internally)
 *
 *      EFFECTS
 *              Empties the TOM_MIGRATE_HASHBASE hash bucket.
 *              Temporarily Enables Interrupts internally
 */

void
tomMigrateAll (void)
{

    toe_t   *ptoe;
    ulong_t itow;                       // Hash bucket index.
    ulong_t cmsec;                      // Time until destination time.
    ulong_t mscount;                    // new time out  - //93353

    tomProfile(ctomMigrateAll);

    while (atowHash[TOM_MIGRATE_HASHBASE].tow_ptoePrev !=
           (toe_t *) &atowHash[TOM_MIGRATE_HASHBASE]) {

        tomProfile(ctomMigrate);

        // Get and unlink the last migrating timer. (Optimized TOMCancel)

        ptoe = atowHash[TOM_MIGRATE_HASHBASE].tow_ptoePrev;
        ptoe-> toe_ptoeNext-> toe_ptoePrev = ptoe-> toe_ptoePrev;
        ptoe-> toe_ptoePrev-> toe_ptoeNext = ptoe-> toe_ptoeNext;

        tomAssertLinkedToe(ptoe);
        tomAssertLinkedItow(TOM_MIGRATE_HASHBASE);

        // Migrate the timer.

        if (SISData.SIS_MsCount < ptoe->toe_mscount)                             //93353
            mscount = 0xffffffff - ptoe->toe_mscount + SISData.SIS_MsCount + 1;  //93353
        else                                                                     //93353
            mscount = SISData.SIS_MsCount - ptoe->toe_mscount;                   //93353

//93353   if (SISData.SIS_MsCount >= ptoe-> toe_cmsec) {
        if (mscount >= ptoe-> toe_cmsec) {    //if time left >= timeout parameter - 93353

            // Timer's expiration time has come or past.  Cancel and fire it.
            // Timers must be cancelled before they are fired, otherwise
            // subsequent cancels on the fired timer will ruin links.

#if defined (TOM_PROFILE)
            tomCheckFire(ptoe);
#endif

            ptoe-> toe_ptoeNext = ptoe;  // timer must be cancelled first...
            ptoe-> toe_ptoePrev = ptoe;  // ... to allow more cancelling
            ENABLE();
            // TomSet, TomCancel can occur here.
            TOMapfn[ptoe->toe_worker & TOM_WORKER_MASK] (ptoe);
            DISABLE();
            tomProfile(ctomFire);

        } else {  // timer has to be relinked into the hash tables.

//93353            cmsec = ptoe-> toe_cmsec - SISData.SIS_MsCount;
            cmsec = ptoe-> toe_cmsec - mscount;   //93353

            if ((!(ptoe-> toe_worker & TOM_HIRES_FLAG)) ||
                (ptoe-> toe_cmsec >=
                (mscount + TOM_HIRES_HASHTIME))) {
//                (SISData.SIS_MsCount + TOM_HIRES_HASHTIME))) {

                // All normal timers, and any hi resolution timers
                // that are at least 128ms away get reinserted
                // into the 32ms resolution hash buckets.

                if (cmsec & TOM_ORDER0_LIMIT_MASK) {
                    if (cmsec & TOM_ORDER1_LIMIT_MASK) {
                        if (cmsec & TOM_ORDER2_LIMIT_MASK) {
                            if (cmsec & TOM_ORDER3_LIMIT_MASK) {
                                if (cmsec & TOM_ORDER4_LIMIT_MASK) {
                                        tomProfile(cMigrateOrder5);
                                        itow = TOM_ORDER5_HASHBASE;
                                } else {
                                    tomProfile(cMigrateOrder4);
                                    itow = TOM_ORDER4_HASHBASE;
                                }
                            } else {
                                tomProfile(cMigrateOrder3);
                                itow = TOM_ORDER3_HASHBASE +
                                  (((ptoe-> toe_cmsec + ptoe->toe_mscount) &
                                                        TOM_ORDER3_MASK) >>
                                                       TOM_ORDER3_SHIFT);
                            }
                        } else {
                            tomProfile(cMigrateOrder2);
                            itow = TOM_ORDER2_HASHBASE +
                              (((ptoe-> toe_cmsec + ptoe->toe_mscount) &
                                                    TOM_ORDER2_MASK) >>
                                                   TOM_ORDER2_SHIFT);
                        }
                    } else {
                        tomProfile(cMigrateOrder1);
                        itow = TOM_ORDER1_HASHBASE +
                          (((ptoe-> toe_cmsec + ptoe->toe_mscount) &
                                                TOM_ORDER1_MASK) >>
                                               TOM_ORDER1_SHIFT);
                    }
                } else {
                    if (cmsec >= TOM_32MS_TICK) {
                        tomProfile(cMigrateOrder0);
                        itow = TOM_ORDER0_HASHBASE +
                          (((ptoe-> toe_cmsec + ptoe->toe_mscount) &
                                               TOM_ORDER0_MASK) >>
                                               TOM_ORDER0_SHIFT);
                    } else {

                        // Normal resolution timer < 32ms away;  This timer
                        // was on the "2nd half" of the previous bucket; ie,
                        // it was still 1-31ms greater than system time when
                        // its bucket was examined.  It is to expire at the
                        // beginning of the next 32ms tick.

                        tomProfile(cMigrateNext32);
                        itow = TOM_NEXT32_HASHBASE;
                    }
                }

//            } else if (ptoe-> toe_cmsec > SISData.SIS_MsCount) {
            } else if (ptoe-> toe_cmsec > mscount) {

                // Hi resolution timer 1-127ms away.

                if (cmsec >= TOM_8MS_TICK) {

                    itow = TOM_HIRES_HASHBASE +
                      (((ptoe-> toe_cmsec + ptoe->toe_mscount) &
                                            TOM_HIRES_MASK) >>
                                           TOM_HIRES_SHIFT);

                } else {

                    // Hi resolution timer < 8ms away;  This timer
                    // was on the "2nd half" of the previous bucket; ie,
                    // it was still 1-7ms greater than system time when
                    // its bucket was examined.  It is to expire at the
                    // beginning of the next 8ms tick.

                    itow = TOM_NEXT8_HASHBASE;
                }

                if (!tomHiResPending) {
                    cmsecHiResTomTime = SISData.SIS_MsCount;
                    FreqSet(128);
                    tomProfile(ctom128hz)
                }

                tomProfile(cMigrateHiRes[itow]);
                tomHiResPending |= (1 << itow);
            }

            // itow now indexes the right spot in the hash table.
            // Insert the toe at the head of that list.  We use
            // the head during migration to get round-robin.

            ptoe-> toe_ptoeNext = atowHash[itow].tow_ptoeNext;
            ptoe-> toe_ptoePrev = (toe_t *) &(atowHash + itow);
            atowHash[itow].tow_ptoeNext-> toe_ptoePrev = ptoe;
            atowHash[itow].tow_ptoeNext = ptoe;

            tomAssertLinkedToe(ptoe);
            tomAssertLinkedItow(itow);

            ENABLE();
            TKBitBucket = 0;        // Interrupts can occur here.
            // Additional sets and cancels may occur here during migration.
            DISABLE();
        }

        // During this migration loop, we enable interrupts.  SystemTime
        // could advance.  Since the hi res timer buckets are only 128ms
        // wide, a time advance could put newly migrating hi res timers "on
        // top of" old hi res timers.  When such a bucket migrates, the
        // "past time" timers will be fired, and the newer timers will
        // be reinserted.  This results in some extra work, but it would
        // be more work to prevent the overlapping condition, which does
        // not typically occur.

    }
}



// ******  START of FAKE TOM WORKERS FOR LINKING  ******
// Remove these declarations as these workers are added to the
// system.  Once all of these worker routines are added to the
// system, this entire section will be eliminated.

void    VDMMTomHook     (toe_t *ptoe) {}

// ******  END of FAKE TOM WORKERS FOR LINKING  ******



// ******  START of TOM Testing Routine  ******
// This next section is used for testing the TOM component.
// This should not normally be included in the kernel.  To
// "enable" this test, simply define TOMTESTWORKER before compiling.

#ifdef TOMTESTWORKER

#define TOMTEST_MAX     4096

struct  tomtest_s {
        toe_t  tomtest_toe;
        ulong_t tomtest_CallCount;
};

typedef struct  tomtest_s tomtest_t;

tomtest_t atomtest [TOMTEST_MAX];

ulong_t WorkerCallCount;

void tomTest (void)
{
    ulong_t i;

    // Do we call the worker?   Can the worker be periodic?
    // Was the timing correct?
    WorkerCallCount = 0;
    atomtest[0].tomtest_CallCount = 0;
    TOMSet(&atomtest[0].tomtest_toe,1000,TOM_W_TEST);

    // Busy loop one minute.  Take interrupts only at this point.
    while (WorkerCallCount < 60) {
    };

    // Verify 1 minute has elapsed, using a stopwatch.

    DISABLE();
    tomAssert(WorkerCallCount == atomtest[0].tomtest_CallCount);

    // Can we cancel the worker while it is set?
    TOMCancel(&atomtest[0].tomtest_toe);

    WorkerCallCount = 0;
    atomtest[0].tomtest_CallCount = 0;

    ENABLE();

    // Do we call the worker anymore?  Set a breakpoint on the worker
    // and busy loop for 10 seconds if worker gets called.  If not,
    // then fine.  It should be necessary to use the debugger to exit
    // this while loop.
    while (WorkerCallCount < 10) {
    };

    tomAssert(WorkerCallCount == 0);

    // Set a whole bunch of timers with interrupts enabled and
    // decreasing start times, then cancel them all.  As these
    // are periodic timers, the Cancels should all work OK.

    for (i=0; i < TOMTEST_MAX; i++) {
        TOMSet(&atomtest[i].tomtest_toe,(TOMTEST_MAX-i) * 10,TOM_W_TEST);
    }

    // Wait until each timer fires at least once.  This should
    // take about 41 seconds, plus some overhead.
    for (i=0; i < TOMTEST_MAX; i++) {
        while (atomtest[i].tomtest_CallCount == 0)
            ;
    }

    // Cancel all the timers.
    for (i=0; i < TOMTEST_MAX; i++) {
        TOMCancel(&atomtest[i].tomtest_toe);
    }

    DISABLE();

    // Verify that WorkerCallCount equals the sum of the timer calls.
    for (i=0; i < TOMTEST_MAX; i++) {
        WorkerCallCount -= atomtest[i].tomtest_CallCount;
    }

    tomAssert(WorkerCallCount == 0);

    ENABLE();

    // The Test Has Passed.
    tomAssert(FALSE);
}

/*
 * One-second periodic test timer.
 */

void tomTestWorker (toe_t *ptoe)
{
    ++WorkerCallCount;
    ++((tomtest_t *) ptoe)->tomtest_CallCount;
    TOMSet(ptoe,1000,TOM_W_TEST);
}

#endif
// ******  END of TOM Testing Routine  ******
