test: timers.c Source File

Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

# timers.c

Go to the documentation of this file.

    00001 /****************************** Module Header ******************************\
    00002 * Module Name: timers.c
    00003 *
    00004 * Copyright (c) 1985 - 1999, Microsoft Corporation
    00005 *
    00006 * This module contains the user timer APIs and support routines.
    00007 *
    00008 * History:
    00009 * 12-Nov-1990 DarrinM   Created.
    00010 * 08-Apr-1992 DarrinM   Switched to PM/Win3-like ScanTimers model.
    00011 \***************************************************************************/
    00012
    00013 #define _TIMERS 1      // uses a LARGE_INTEGER
    00014 #include "precomp.h"
    00015 #pragma hdrstop
    00016
    00017
    00018 /*
    00019  * Make sure that if we return a timer id that it is a WORD value. This
    00020  * will ensure that WOW doesn't need to handle-translate return values
    00021  * from SetTimer().
    00022  *
    00023  * Start with a large number so that FindTimer() doesn't find a timer we
    00024  * calculated with a low cTimerId if the app happens to pass in NULL pwnd
    00025  * and a low id (like 1).
    00026  */
    00027 #define TIMERID_MAX   0x7FFF
    00028 #define TIMERID_MIN   0x100
    00029
    00030 #define ELAPSED_MAX  0x7FFFFFFF
    00031
    00032 #define SYSRIT_TIMER  (TMRF_SYSTEM | TMRF_RIT)
    00033
    00034 WORD cTimerId = TIMERID_MAX;
    00035
    00036 /***************************************************************************\
    00037 * _SetTimer (API)
    00038 *
    00039 * This API will start the specified timer.
    00040 *
    00041 * History:
    00042 * 15-Nov-1990 DavidPe   Created.
    00043 \***************************************************************************/
    00044
    00045 UINT_PTR _SetTimer(
    00046     PWND         pwnd,
    00047     UINT_PTR     nIDEvent,
    00048     UINT         dwElapse,
    00049     TIMERPROC_PWND pTimerFunc)
    00050 {
    00051     /*
    00052      * Prevent apps from setting a Timer with a window proc to another app
    00053      */
    00054     if (pwnd && (PpiCurrent() != GETPTI(pwnd)->ppi)) {
    00055
    00056         RIPERR1(ERROR_ACCESS_DENIED,
    00057                 RIP_WARNING,
    00058                 "Calling SetTimer with window of another process %lX",
    00059                 pwnd);
    00060
    00061         return 0;
    00062     }
    00063
    00064     return InternalSetTimer(pwnd, nIDEvent, dwElapse, pTimerFunc, 0);
    00065 }
    00066
    00067 /***************************************************************************\
    00068 * _SetSystemTimer
    00069 *
    00070 * This API will start start a system timer which will generate WM_SYSTIMER
    00071 * messages rather than WM_TIMER
    00072 *
    00073 * History:
    00074 * 15-Nov-1990 DavidPe   Created.
    00075 * 21-Jan-1991 IanJa     Prefix '_' denotes export function (not API)
    00076 \***************************************************************************/
    00077
    00078 UINT_PTR _SetSystemTimer(
    00079     PWND         pwnd,
    00080     UINT_PTR     nIDEvent,
    00081     DWORD        dwElapse,
    00082     TIMERPROC_PWND pTimerFunc)
    00083 {
    00084     /*
    00085      * Prevent apps from setting a Timer with a window proc to another app
    00086      */
    00087     if (pwnd && PpiCurrent() != GETPTI(pwnd)->ppi) {
    00088
    00089         RIPERR1(ERROR_ACCESS_DENIED,
    00090                 RIP_WARNING,
    00091                 "Calling SetSystemTimer with window of another process %lX",
    00092                 pwnd);
    00093
    00094         return 0;
    00095     }
    00096
    00097     return InternalSetTimer(pwnd, nIDEvent, dwElapse, pTimerFunc, TMRF_SYSTEM);
    00098 }
    00099
    00100 /***************************************************************************\
    00101 * FreeTimer
    00102 *
    00103 * This function does the actual unlinking and freeing of the timer structure.
    00104 * I pulled it out of FindTimer() so it could be shared with DestroyQueues-
    00105 * Timers.
    00106 * Sets *pptmr to point to the next TIMER struct (NULL if none)
    00107 *
    00108 * History:
    00109 * 15-Feb-1991 DarrinM   Pulled from FindTimer().
    00110 \***************************************************************************/
    00111
    00112 VOID FreeTimer(
    00113     PTIMER ptmr) {
    00114
    00115     CheckCritIn();
    00116
    00117     /*
    00118      * Mark it for destruction.  If it the object is locked it can't
    00119      * be freed right now.
    00120      */
    00121     if (!HMMarkObjectDestroy((PVOID)ptmr))
    00122         return;
    00123
    00124     /*
    00125      * If this timer was just about to be processed, decrement
    00126      * the ready-count since we're blowing it off.
    00127      */
    00128     if (ptmr->flags & TMRF_READY)
    00129         DecTimerCount(ptmr->pti);
    00130
    00131     /*
    00132      * Unlock the window
    00133      */
    00134     Unlock(&ptmr->spwnd);
    00135
    00136     /*
    00137      * Unlink this timer
    00138      */
    00139     if (ptmr->ptmrPrev) {
    00140         ptmr->ptmrPrev->ptmrNext = ptmr->ptmrNext;
    00141     } else {
    00142         gptmrFirst = ptmr->ptmrNext;
    00143     }
    00144
    00145     if (ptmr->ptmrNext) {
    00146         ptmr->ptmrNext->ptmrPrev = ptmr->ptmrPrev;
    00147     }
    00148
    00149     /*
    00150      * Free up the TIMER structure.
    00151      */
    00152     HMFreeObject((PVOID)ptmr);
    00153 }
    00154
    00155
    00156 /***************************************************************************\
    00157 * FindTimer
    00158 *
    00159 * This function will find a timer that matches the parameters.  We also
    00160 * deal with killing timers here since it's easier to remove items from
    00161 * the list while we're scanning it.
    00162 *
    00163 * History:
    00164 * 15-Nov-1990 DavidPe   Created.
    00165 \***************************************************************************/
    00166
    00167 PTIMER FindTimer(
    00168     PWND pwnd,
    00169     UINT_PTR nID,
    00170     UINT flags,
    00171     BOOL fKill)
    00172 {
    00173     PTIMER ptmr;
    00174
    00175     ptmr = gptmrFirst;
    00176
    00177     while (ptmr != NULL) {
    00178
    00179         /*
    00180          * Is this the timer we're looking for?
    00181          */
    00182         if ((ptmr->spwnd == pwnd) &&
    00183             (ptmr->nID == nID)    &&
    00184             (ptmr->flags & SYSRIT_TIMER) == (flags & SYSRIT_TIMER)) {
    00185
    00186             /*
    00187              * Are we being called from KillTimer()? If so, destroy the
    00188              * timer.  return != 0 because *pptmr is gone.
    00189              */
    00190             if (fKill) {
    00191                 FreeTimer(ptmr);
    00192                 return (PTIMER)TRUE;
    00193             }
    00194
    00195             /*
    00196              * Found the timer, break out of the loop.
    00197              */
    00198             break;
    00199         }
    00200
    00201         /*
    00202          * No, try the next one.
    00203          */
    00204         ptmr = ptmr->ptmrNext;
    00205     }
    00206
    00207     return ptmr;
    00208 }
    00209
    00210 /***************************************************************************\
    00211 * InternalSetTimer
    00212 *
    00213 * This is the guts of SetTimer that actually gets things going.
    00214 *
    00215 * NOTE (darrinm): Technically there is a bit of latency (the time it takes
    00216 * between SetTimer's NtSetEvent and when the RIT wakes up and calls ScanTimers)
    00217 * between when SetTimer is called and when the counter starts counting down.
    00218 * This is uncool but it should be a very short amount of time because the RIT
    00219 * is high-priority.  If it becomes a problem I know how to fix it.
    00220 *
    00221 * History:
    00222 * 15-Nov-1990 DavidPe      Created.
    00223 \***************************************************************************/
    00224
    00225 UINT_PTR InternalSetTimer(
    00226     PWND         pwnd,
    00227     UINT_PTR     nIDEvent,
    00228     UINT         dwElapse,
    00229     TIMERPROC_PWND pTimerFunc,
    00230     UINT         flags)
    00231 {
    00232     LARGE_INTEGER liT = {1, 0};
    00233     PTIMER        ptmr;
    00234     PTHREADINFO   ptiCurrent;
    00235
    00236     CheckCritIn();
    00237
    00238     /*
    00239      * Assert if someone tries to set a timer after InitiateWin32kCleanup
    00240      * killed the RIT.
    00241      */
    00242     UserAssert(gptiRit != NULL);
    00243
    00244     /*
    00245      * 1.0 compatibility weirdness. Also, don't allow negative elapse times
    00246      * because this'll cause ScanTimers() to generate negative elapse times
    00247      * between timers.
    00248      */
    00249     if ((dwElapse == 0) || (dwElapse > ELAPSED_MAX))
    00250         dwElapse = 1;
    00251
    00252     /*
    00253      * Attempt to first locate the timer, then create a new one
    00254      * if one isn't found.
    00255      */
    00256     if ((ptmr = FindTimer(pwnd, nIDEvent, flags, FALSE)) == NULL) {
    00257
    00258         /*
    00259          * Not found.  Create a new one.
    00260          */
    00261         ptmr = (PTIMER)HMAllocObject(NULL, NULL, TYPE_TIMER, sizeof(TIMER));
    00262         if (ptmr == NULL) {
    00263             return 0;
    00264         }
    00265
    00266         ptmr->spwnd = NULL;
    00267
    00268         if (pwnd == NULL) {
    00269
    00270             WORD timerIdInitial = cTimerId;
    00271
    00272             /*
    00273              * Pick a unique, unused timer ID.
    00274              */
    00275             do {
    00276
    00277                 if (--cTimerId <= TIMERID_MIN)
    00278                     cTimerId = TIMERID_MAX;
    00279
    00280                 if (cTimerId == timerIdInitial) {
    00281
    00282                     /*
    00283                      * Flat out of timers bud.
    00284                      */
    00285                     HMFreeObject(ptmr);
    00286                     return 0;
    00287                 }
    00288
    00289             } while (FindTimer(NULL, cTimerId, flags, FALSE) != NULL);
    00290
    00291             ptmr->nID = (UINT)cTimerId;
    00292
    00293         } else {
    00294             ptmr->nID = nIDEvent;
    00295         }
    00296
    00297         /*
    00298          * Link the new timer into the front of the list.
    00299          * Handily this works even when gptmrFirst is NULL.
    00300          */
    00301         ptmr->ptmrNext = gptmrFirst;
    00302         ptmr->ptmrPrev = NULL;
    00303         if (gptmrFirst)
    00304             gptmrFirst->ptmrPrev = ptmr;
    00305         gptmrFirst = ptmr;
    00306
    00307     } else {
    00308
    00309         /*
    00310          * If this timer was just about to be processed,
    00311          * decrement cTimersReady since we're resetting it.
    00312          */
    00313         if (ptmr->flags & TMRF_READY)
    00314             DecTimerCount(ptmr->pti);
    00315     }
    00316
    00317     /*
    00318      * If pwnd is NULL, create a unique id by
    00319      * using the timer handle.  RIT timers are 'owned' by the RIT pti
    00320      * so they are not deleted when the creating pti dies.
    00321      *
    00322      * We used to record the pti as the pti of the window if one was
    00323      * specified.  This is not what Win 3.1 does and it broke 10862
    00324      * where some merge app was setting the timer on winword's window
    00325      * it it still expected to get the messages not winword.
    00326      *
    00327      * MS Visual C NT was counting on this bug in the NT 3.1 so if
    00328      * a thread sets a timer for a window in another thread in the
    00329      * same process the timer goes off in the thread of the window.
    00330      * You can see this by doing a build in msvcnt and the files being
    00331      * compiled do not show up.
    00332      */
    00333     ptiCurrent = (PTHREADINFO)(W32GetCurrentThread()); /*
    00334                                                         * This will be NULL
    00335                                                         * for a non-GUI thread.
    00336                                                         */
    00337
    00338     if (pwnd == NULL) {
    00339
    00340         if (flags & TMRF_RIT) {
    00341             ptmr->pti = gptiRit;
    00342         } else {
    00343             ptmr->pti = ptiCurrent;
    00344             UserAssert(ptiCurrent);
    00345         }
    00346
    00347     } else {
    00348
    00349         /*
    00350          * As enforced in the API wrappers.  We shouldn't get here
    00351          * any other way for an app timer.
    00352          *
    00353          * Always use pti of the window when TMRF_PTIWINDOW is passed in.
    00354          */
    00355         if ((ptiCurrent->TIF_flags & TIF_16BIT) && !(flags & TMRF_PTIWINDOW)) {
    00356             ptmr->pti = ptiCurrent;
    00357             UserAssert(ptiCurrent);
    00358         } else {
    00359             ptmr->pti = GETPTI(pwnd);
    00360         }
    00361     }
    00362
    00363     /*
    00364      * Initialize the timer-struct.
    00365      *
    00366      * NOTE: The ptiOptCreator is used to identify a JOURNAL-timer.  We
    00367      *       want to allow these timers to be destroyed when the creator
    00368      *       thread goes away.  For other threads that create timers across
    00369      *       threads, we do not want to destroy these timers when the
    00370      *       creator goes away.  Currently, we're only checking for a
    00371      *       TMRF_RIT.  However, in the future we might want to add this
    00372      *       same check for TMRF_SYSTEM.
    00373      */
    00374     Lock(&(ptmr->spwnd), pwnd);
    00375
    00376     ptmr->cmsCountdown  = ptmr->cmsRate = dwElapse;
    00377     ptmr->flags         = flags | TMRF_INIT;
    00378     ptmr->pfn           = pTimerFunc;
    00379     ptmr->ptiOptCreator = (flags & TMRF_RIT ? ptiCurrent : NULL);
    00380
    00381     /*
    00382      * Force the RIT to scan timers.
    00383      *
    00384      * N.B. The following code sets the raw input thread timer to expire
    00385      *      at the absolute time 1 which is very far into the past. This
    00386      *      causes the timer to immediately expire before the set timer
    00387      *      call returns.
    00388      */
    00389     if (ptiCurrent == gptiRit) {
    00390         /*
    00391          * Don't let RIT timer loop reset the master timer - we already have.
    00392          */
    00393         gbMasterTimerSet = TRUE;
    00394     }
    00395
    00396     UserAssert(gptmrMaster);
    00397     KeSetTimer(gptmrMaster, liT, NULL);
    00398
    00399     /*
    00400      * Windows 3.1 returns the timer ID if non-zero, otherwise it returns 1.
    00401      */
    00402     return (ptmr->nID == 0 ? 1 : ptmr->nID);
    00403 }
    00404
    00405 /***************************************************************************\
    00406 * _KillTimer (API)
    00407 *
    00408 * This API will stop a timer from sending WM_TIMER messages.
    00409 *
    00410 * History:
    00411 * 15-Nov-1990 DavidPe   Created.
    00412 \***************************************************************************/
    00413
    00414 BOOL _KillTimer(
    00415     PWND pwnd,
    00416     UINT_PTR nIDEvent)
    00417 {
    00418     return KillTimer2(pwnd, nIDEvent, FALSE);
    00419 }
    00420
    00421 /***************************************************************************\
    00422 * _KillSystemTimer
    00423 *
    00424 * This API will stop a system timer from sending WM_SYSTIMER messages.
    00425 *
    00426 * History:
    00427 * 15-Nov-1990 DavidPe   Created.
    00428 * 21-Jan-1991 IanJa     Prefix '_' denotes export function (not API)
    00429 \***************************************************************************/
    00430
    00431 BOOL _KillSystemTimer(
    00432     PWND pwnd,
    00433     UINT_PTR nIDEvent)
    00434 {
    00435     return KillTimer2(pwnd, nIDEvent, TRUE);
    00436 }
    00437
    00438 /***************************************************************************\
    00439 * KillTimer2
    00440 *
    00441 * This is the guts of KillTimer that actually kills the timer.
    00442 *
    00443 * History:
    00444 * 15-Nov-1990 DavidPe       Created.
    00445 \***************************************************************************/
    00446
    00447 BOOL KillTimer2(
    00448     PWND pwnd,
    00449     UINT_PTR nIDEvent,
    00450     BOOL fSystemTimer)
    00451 {
    00452     /*
    00453      * Call FindTimer() with fKill == TRUE.  This will
    00454      * basically delete the timer.
    00455      */
    00456     return (FindTimer(pwnd,
    00457                       nIDEvent,
    00458                       (fSystemTimer ? TMRF_SYSTEM : 0),
    00459                       TRUE) != NULL);
    00460 }
    00461
    00462 /***************************************************************************\
    00463 * DestroyQueuesTimers
    00464 *
    00465 * This function scans through all the timers and destroys any that are
    00466 * associated with the specified queue.
    00467 *
    00468 * History:
    00469 * 15-Feb-1991 DarrinM   Created.
    00470 \***************************************************************************/
    00471
    00472 VOID DestroyThreadsTimers(
    00473     PTHREADINFO pti)
    00474 {
    00475     PTIMER ptmr;
    00476
    00477     ptmr = gptmrFirst;
    00478
    00479     while (ptmr != NULL) {
    00480
    00481         /*
    00482          * Is this one of the timers we're looking for?  If so, destroy it.
    00483          */
    00484         if (ptmr->pti == pti || ptmr->ptiOptCreator == pti) {
    00485             PTIMER ptmrNext = ptmr->ptmrNext;
    00486             FreeTimer(ptmr);
    00487             ptmr = ptmrNext;
    00488         } else {
    00489             ptmr = ptmr->ptmrNext;
    00490         }
    00491     }
    00492 }
    00493
    00494 /***************************************************************************\
    00495 * DestroyWindowsTimers
    00496 *
    00497 * This function scans through all the timers and destroys any that are
    00498 * associated with the specified window.
    00499 *
    00500 * History:
    00501 * 04-Jun-1991 DarrinM       Created.
    00502 \***************************************************************************/
    00503
    00504 VOID DestroyWindowsTimers(
    00505     PWND pwnd)
    00506 {
    00507     PTIMER ptmr;
    00508
    00509     ptmr = gptmrFirst;
    00510
    00511     while (ptmr != NULL) {
    00512
    00513         /*
    00514          * Is this one of the timers we're looking for?  If so, destroy it.
    00515          */
    00516         if (ptmr->spwnd == pwnd) {
    00517             PTIMER ptmrNext = ptmr->ptmrNext;
    00518             FreeTimer(ptmr);
    00519             ptmr = ptmrNext;
    00520         } else {
    00521             ptmr = ptmr->ptmrNext;
    00522         }
    00523     }
    00524 }
    00525
    00526 /***************************************************************************\
    00527 * DoTimer
    00528 *
    00529 * This function gets called from xxxPeekMessage() if the QS_TIMER bit is
    00530 * set.  If this timer is okay with the filter specified the appropriate
    00531 * WM_*TIMER message will be placed in 'pmsg' and the timer will be reset.
    00532 *
    00533 * History:
    00534 * 15-Nov-1990 DavidPe   Created.
    00535 * 27-NOv-1991 DavidPe   Changed to move 'found' timers to end of list.
    00536 \***************************************************************************/
    00537
    00538 BOOL DoTimer(
    00539     PWND pwndFilter)
    00540 {
    00541     PTHREADINFO pti;
    00542     PTIMER      ptmr;
    00543     PTIMER      ptmrNext;
    00544     PQMSG       pqmsg;
    00545
    00546     CheckCritIn();
    00547
    00548     pti = PtiCurrent();
    00549
    00550     /*
    00551      * Search for a timer that belongs to this queue.
    00552      */
    00553     ptmr = gptmrFirst;
    00554
    00555     while (ptmr != NULL) {
    00556
    00557         /*
    00558          * Has this timer gone off and is it one we're looking for?
    00559          */
    00560         if ((ptmr->flags & TMRF_READY) &&
    00561             (ptmr->pti == pti)         &&
    00562             CheckPwndFilter(ptmr->spwnd, pwndFilter)) {
    00563
    00564             /*
    00565              * We found an appropriate timer. Put it in the app's queue and
    00566              * return success.
    00567              */
    00568             if ((pqmsg = AllocQEntry(&pti->mlPost)) != NULL) {
    00569
    00570                 /*
    00571                  * Store the message and set the QS_POSTMESSAGE bit so the
    00572                  * thread knows it has a message.
    00573                  */
    00574                 StoreQMessage(pqmsg,
    00575                               ptmr->spwnd,
    00576                               (UINT)((ptmr->flags & TMRF_SYSTEM) ?
    00577                                       WM_SYSTIMER : WM_TIMER),
    00578                               (WPARAM)ptmr->nID,
    00579                               (LPARAM)ptmr->pfn,
    00580                               0, 0, 0);
    00581 #ifdef REDIRECTION
    00582                 StoreQMessagePti(pqmsg, pti);
    00583 #endif // REDIRECTION
    00584                 SetWakeBit(pti, QS_POSTMESSAGE | QS_ALLPOSTMESSAGE);
    00585             }
    00586
    00587             /*
    00588              * Reset this timer.
    00589              */
    00590             ptmr->flags &= ~TMRF_READY;
    00591             DecTimerCount(ptmr->pti);
    00592
    00593             /*
    00594              * If there are other timers in the system move this timer
    00595              * to the end of the list so other timers in for this queue
    00596              * get a chance to go off.
    00597              */
    00598             ptmrNext = ptmr->ptmrNext;
    00599             if (ptmrNext != NULL) {
    00600
    00601                 /*
    00602                  * Remove ptmr from its place in the list.
    00603                  */
    00604                 if (ptmr->ptmrPrev) {
    00605                     ptmr->ptmrPrev->ptmrNext = ptmr->ptmrNext;
    00606                 } else
    00607                     gptmrFirst = ptmr->ptmrNext;
    00608
    00609                 ptmrNext->ptmrPrev = ptmr->ptmrPrev;
    00610
    00611                 /*
    00612                  * Move to the last TIMER of the list.
    00613                  */
    00614                 while (ptmrNext->ptmrNext != NULL)
    00615                     ptmrNext = ptmrNext->ptmrNext;
    00616
    00617                 /*
    00618                  * Insert this timer at the end.
    00619                  */
    00620                 ptmrNext->ptmrNext = ptmr;
    00621                 ptmr->ptmrPrev = ptmrNext;
    00622                 ptmr->ptmrNext     = NULL;
    00623             }
    00624
    00625             return TRUE;
    00626         }
    00627
    00628         ptmr = ptmr->ptmrNext;
    00629     }
    00630
    00631     return FALSE;
    00632 }
    00633
    00634 /***************************************************************************\
    00635 * DecTimerCount
    00636 *
    00637 * This routine decrements cTimersReady and clears QS_TIMER if the count
    00638 * goes down to zero.
    00639 *
    00640 * History:
    00641 * 21-Jan-1991 DavidPe   Created.
    00642 \***************************************************************************/
    00643
    00644 VOID DecTimerCount(
    00645     PTHREADINFO pti)
    00646 {
    00647     CheckCritIn();
    00648
    00649     if (--pti->cTimersReady == 0)
    00650         pti->pcti->fsWakeBits &= ~QS_TIMER;
    00651 }
    00652
    00653 /***************************************************************************\
    00654 * JournalTimer
    00655 *
    00656 *
    00657 * History:
    00658 * 04-Mar-1991 DavidPe       Created.
    00659 \***************************************************************************/
    00660
    00661 VOID JournalTimer(
    00662     PWND  pwnd,
    00663     UINT  message,
    00664     UINT_PTR nID,
    00665     LPARAM lParam)
    00666 {
    00667     PTHREADINFO pti;
    00668
    00669     DBG_UNREFERENCED_PARAMETER(pwnd);
    00670     DBG_UNREFERENCED_PARAMETER(message);
    00671     DBG_UNREFERENCED_PARAMETER(nID);
    00672
    00673     /*
    00674      * We've already entered the critical section.
    00675      */
    00676     if (pti = ((PTIMER)lParam)->ptiOptCreator)
    00677         WakeSomeone(pti->pq, pti->pq->msgJournal, NULL);
    00678
    00679     return;
    00680 }
    00681
    00682 /***************************************************************************\
    00683 * SetJournalTimer
    00684 *
    00685 * Sets an NT timer that goes off in 'dt' milliseconds and will wake
    00686 * up 'pti' at that time.  This is used in journal playback code to
    00687 * simulate the timing in which events were originally given to the system.
    00688 *
    00689 * History:
    00690 * 04-Mar-1991 DavidPe       Created.
    00691 \***************************************************************************/
    00692
    00693 void SetJournalTimer(
    00694     DWORD dt,
    00695     UINT  msgJournal)
    00696 {
    00697     static UINT_PTR idJournal = 0;
    00698
    00699     PtiCurrent()->pq->msgJournal = msgJournal;
    00700
    00701     /*
    00702      * Remember idJournal - because TMRF_ONESHOT timers stay in the timer
    00703      * list - by remembering the idJournal, we always reuse the same timer
    00704      * rather than creating new ones always.
    00705      */
    00706     idJournal = InternalSetTimer(NULL,
    00707                                  idJournal,
    00708                                  dt,
    00709                                  JournalTimer,
    00710                                  TMRF_RIT | TMRF_ONESHOT);
    00711 }
    00712
    00713 /***************************************************************************\
    00714 * StartTimers
    00715 *
    00716 * Prime the timer pump by starting the cursor restoration timer.
    00717 *
    00718 * History:
    00719 * 02-Apr-1992 DarrinM   Created.
    00720 \***************************************************************************/
    00721
    00722 UINT_PTR StartTimers(VOID)
    00723 {
    00724     /*
    00725      * Let GDI know that it can start settings timers on the RIT.
    00726      */
    00727     GreStartTimers();
    00728
    00729     /*
    00730      * TMRF_RIT timers are called directly from ScanTimers -- no nasty
    00731      * thread switching for these boys.
    00732      */
    00733     return InternalSetTimer(NULL, 0, 1000, xxxHungAppDemon, TMRF_RIT);
    00734 }
    00735
    00736
    00737 /***************************************************************************\
    00738 * TimersProc
    00739 *
    00740 * Deal with the timers. Called from RawInputThread.
    00741 *
    00742 * History:
    00743 * 11-11-1996 CLupu   Created.
    00744 \***************************************************************************/
    00745
    00746 VOID TimersProc(
    00747     VOID)
    00748 {
    00749     INT            dmsSinceLast;
    00750     LARGE_INTEGER  liT;
    00751     PTIMER         ptmr;
    00752     DWORD          cmsCur;
    00753
    00754     /*
    00755      * Calculate how long it was since the last time we
    00756      * processed timers so we can subtract that much time
    00757      * from each timer's countdown value.
    00758      */
    00759     EnterCrit();
    00760
    00761     cmsCur = NtGetTickCount();
    00762     dmsSinceLast = ComputePastTickDelta(cmsCur, gcmsLastTimer);
    00763     gcmsLastTimer = cmsCur;
    00764
    00765     /*
    00766      * dmsNextTimer is the time delta before the next
    00767      * timer should go off.  As we loop through the
    00768      * timers below this will shrink to the smallest
    00769      * cmsCountdown value in the list.
    00770      */
    00771     gdmsNextTimer = 0x7FFFFFFF;
    00772     ptmr = gptmrFirst;
    00773     gbMasterTimerSet = FALSE;
    00774     while (ptmr != NULL) {
    00775
    00776         /*
    00777          * ONESHOT timers go to a WAITING state after
    00778          * they go off. This allows us to leave them
    00779          * in the list but keep them from going off
    00780          * over and over.
    00781          */
    00782         if (ptmr->flags & TMRF_WAITING) {
    00783             ptmr = ptmr->ptmrNext;
    00784             continue;
    00785         }
    00786
    00787         /*
    00788          * The first time we encounter a timer we don't
    00789          * want to set it off, we just want to use it to
    00790          * compute the shortest countdown value.
    00791          */
    00792         if (ptmr->flags & TMRF_INIT) {
    00793             ptmr->flags &= ~TMRF_INIT;
    00794
    00795         } else {
    00796             /*
    00797              * If this timer is going off, wake up its
    00798              * owner.
    00799              */
    00800             ptmr->cmsCountdown -= dmsSinceLast;
    00801             if (ptmr->cmsCountdown <= 0) {
    00802                 ptmr->cmsCountdown = ptmr->cmsRate;
    00803
    00804                 /*
    00805                  * If the timer's owner hasn't handled the
    00806                  * last time it went off yet, throw this event
    00807                  * away.
    00808                  */
    00809                 if (!(ptmr->flags & TMRF_READY)) {
    00810                     /*
    00811                      * A ONESHOT timer goes into a WAITING state
    00812                      * until SetTimer is called again to reset it.
    00813                      */
    00814                     if (ptmr->flags & TMRF_ONESHOT)
    00815                         ptmr->flags |= TMRF_WAITING;
    00816
    00817                     /*
    00818                      * RIT timers have the distinction of being
    00819                      * called directly and executing serially with
    00820                      * with incoming timer events.
    00821                      * NOTE: RIT timers get called while we're
    00822                      * inside the critical section.
    00823                      */
    00824                     if (ptmr->flags & TMRF_RIT) {
    00825                         TL tlTimer;
    00826
    00827                         ThreadLock(ptmr, &tlTimer);
    00828                         /*
    00829                          * May set gbMasterTimerSet
    00830                          */
    00831                         (ptmr->pfn)(NULL,
    00832                                     WM_SYSTIMER,
    00833                                     ptmr->nID,
    00834                                     (LPARAM)ptmr);
    00835
    00836                         if (HMIsMarkDestroy(ptmr)) {
    00837                             ptmr = ptmr->ptmrNext;
    00838                             ThreadUnlock(&tlTimer);
    00839                             continue;
    00840                         }
    00841                         ThreadUnlock(&tlTimer);
    00842
    00843                     } else {
    00844                         ptmr->flags |= TMRF_READY;
    00845                         ptmr->pti->cTimersReady++;
    00846                         SetWakeBit(ptmr->pti, QS_TIMER);
    00847                     }
    00848                 }
    00849             }
    00850         }
    00851
    00852         /*
    00853          * Remember the shortest time left of the timers.
    00854          */
    00855         if (ptmr->cmsCountdown < gdmsNextTimer)
    00856             gdmsNextTimer = ptmr->cmsCountdown;
    00857
    00858         /*
    00859          * Advance to the next timer structure.
    00860          */
    00861         ptmr = ptmr->ptmrNext;
    00862     }
    00863
    00864     if (!gbMasterTimerSet) {
    00865         /*
    00866          * Time in NT should be negative to specify a relative
    00867          * time. It's also in hundred nanosecond units so multiply
    00868          * by 10000  to get the right value from milliseconds.
    00869          */
    00870         liT.QuadPart = Int32x32To64(-10000, gdmsNextTimer);
    00871         KeSetTimer(gptmrMaster, liT, NULL);
    00872     }
    00873
    00874     LeaveCrit();
    00875 }
    00876
    00877 /***************************************************************************\
    00878 *  xxxSystemTimerProc()
    00879 *
    00880 *  11/15/96 GerardoB  Created
    00881 \***************************************************************************/
    00882 VOID xxxSystemTimerProc(PWND pwnd, UINT msg, UINT_PTR id, LPARAM lParam)
    00883 {
    00884     CheckLock(pwnd);
    00885     UNREFERENCED_PARAMETER(msg);
    00886     UNREFERENCED_PARAMETER(id);
    00887     UNREFERENCED_PARAMETER(lParam);
    00888
    00889     switch (id) {
    00890         case IDSYS_LAYER: {
    00891             PDCE pdce;
    00892
    00893             for (pdce = gpDispInfo->pdceFirst; pdce != NULL; pdce = pdce->pdceNext) {
    00894
    00895                 if (pdce->DCX_flags & (DCX_INVALID | DCX_DESTROYTHIS))
    00896                     continue;
    00897
    00898                 if ((pdce->DCX_flags & DCX_LAYERED) && (pdce->DCX_flags & DCX_INUSE)) {
    00899                     UpdateLayeredSprite(pdce);
    00900                 }
    00901             }
    00902         }
    00903         return;
    00904
    00905         case IDSYS_FADE:
    00906             AnimateFade();
    00907             return;
    00908
    00909         case IDSYS_FLASHWND:
    00910             xxxFlashWindow(pwnd, FLASHW_TIMERCALL, 0);
    00911             return;
    00912
    00913         case IDSYS_WNDTRACKING: {
    00914             /*
    00915              * If the active track window hasn't changed,
    00916              *  it's time to active it.
    00917              * spwndTrack can be NULL if it got destroyed but we haven't
    00918              *  destroyed the timer.yet
    00919              */
    00920             PTHREADINFO pti = GETPTI(pwnd);
    00921             UserAssert(TestUP(ACTIVEWINDOWTRACKING));
    00922
    00923             if ((pti->rpdesk->spwndTrack != NULL)
    00924                     && (pwnd == GetActiveTrackPwnd(pti->rpdesk->spwndTrack, NULL))) {
    00925
    00926                 pti->pq->QF_flags |= (QF_ACTIVEWNDTRACKING | QF_MOUSEMOVED);
    00927
    00928 #ifdef REDIRECTION
    00929                 /*
    00930                  * Should we call the hit test hook here ?
    00931                  */
    00932                 PushMouseMove(pti->pq, gpsi->ptCursor);
    00933 #endif // REDIRECTION
    00934
    00935                 SetWakeBit(pti, QS_MOUSEMOVE);
    00936             }
    00937         }
    00938         break;
    00939
    00940         case IDSYS_MOUSEHOVER: {
    00941             PTHREADINFO pti = GETPTI(pwnd);
    00942             PDESKTOP pdesk = pti->rpdesk;
    00943             /*
    00944              * If hover hasn't been canceled, the mouse is still on
    00945              *  this window and the point is still on the rect, then
    00946              *  it's hover time!
    00947              */
    00948             if ((pdesk->dwDTFlags & DF_TRACKMOUSEHOVER)
    00949                     && (HWq(pwnd) == HWq(pdesk->spwndTrack)
    00950                     && PtInRect(&pdesk->rcMouseHover, gpsi->ptCursor))) {
    00951
    00952                 UINT message;
    00953                 WPARAM wParam;
    00954                 POINT pt = gpsi->ptCursor;
    00955
    00956                 if (pdesk->htEx == HTCLIENT) {
    00957                     message = WM_MOUSEHOVER;
    00958                     wParam = (WPARAM)GetMouseKeyFlags(pti->pq);
    00959 #ifdef USE_MIRRORING
    00960                     if (TestWF(pwnd, WEFLAYOUTRTL)) {
    00961                         pt.x = pwnd->rcClient.right - pt.x - 1;
    00962                     } else
    00963 #endif
    00964                     {
    00965                         pt.x -= pwnd->rcClient.left;
    00966                     }
    00967                     pt.y -= pwnd->rcClient.top;
    00968                 } else {
    00969                     message = WM_NCMOUSEHOVER;
    00970                     /*
    00971                      * Map the extended hit test code to a public one.
    00972                      */
    00973                     wParam = (WPARAM)LOWORD(pdesk->htEx);
    00974                     if ((wParam >= HTEXMENUFIRST) && (wParam <= HTEXMENULAST)) {
    00975                         wParam = (WPARAM)HTMENU;
    00976                     } else if ((wParam >= HTEXSCROLLFIRST) && (wParam <= HTEXSCROLLLAST)) {
    00977                         wParam = (WPARAM)(HIWORD(pdesk->htEx) ? HTVSCROLL : HTHSCROLL);
    00978                     }
    00979                 }
    00980
    00981                 _PostMessage(pwnd, message, wParam, MAKELPARAM(pt.x, pt.y));
    00982
    00983                 pdesk->dwDTFlags &= ~DF_TRACKMOUSEHOVER;
    00984                 break;
    00985             }
    00986         }
    00987         return;
    00988
    00989
    00990         default:
    00991             RIPMSG1(RIP_ERROR, "xxxSystemTimerProc: unexpected id:%#lx", id);
    00992             break;
    00993     }
    00994
    00995     /*
    00996      * if we fell through, the timer got to go
    00997      */
    00998     _KillSystemTimer(pwnd, id);
    00999     return;
    01000 }
    01001