test: threads.c File Reference

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

# threads.c File Reference

`#include <ntos.h>`
`#include <ntrtl.h>`
`#include <nturtl.h>`
`#include "ntrtlp.h"`
`#include "threads.h"`

Go to the source code of this file.

## Defines

#define | WORKER_IDLE_TIMEOUT 40000
#define | MAX_WORKER_SLEEP_TIME_EXPONENT 4
#define | IOWORKER_IDLE_TIMEOUT 40000
#define | WAIT_IDLE_TIMEOUT 400000

## Functions

NTSTATUS | RtlRegisterWait (OUT PHANDLE WaitHandle, IN HANDLE Handle, IN WAITORTIMERCALLBACKFUNC Function, IN PVOID Context, IN ULONG Milliseconds, IN ULONG Flags)
NTSTATUS | RtlDeregisterWait (IN HANDLE WaitHandle)
NTSTATUS | RtlDeregisterWaitEx (IN HANDLE WaitHandle, IN HANDLE Event)
NTSTATUS | RtlQueueWorkItem (IN WORKERCALLBACKFUNC Function, IN PVOID Context, IN ULONG Flags)
NTSTATUS | RtlSetIoCompletionCallback (IN HANDLE FileHandle, IN APC_CALLBACK_FUNCTION CompletionProc, IN ULONG Flags)
NTSTATUS | RtlCreateTimerQueue (OUT PHANDLE TimerQueueHandle)
NTSTATUS | RtlDeleteTimerQueue (IN HANDLE TimerQueueHandle)
NTSTATUS | RtlDeleteTimerQueueEx (HANDLE QueueHandle, HANDLE Event)
NTSTATUS | RtlCreateTimer (IN HANDLE TimerQueueHandle, OUT HANDLE *Handle, IN WAITORTIMERCALLBACKFUNC Function, IN PVOID Context, IN ULONG DueTime, IN ULONG Period, IN ULONG Flags)
NTSTATUS | RtlUpdateTimer (IN HANDLE TimerQueueHandle, IN HANDLE Timer, IN ULONG DueTime, IN ULONG Period)
NTSTATUS | RtlDeleteTimer (IN HANDLE TimerQueueHandle, IN HANDLE TimerToCancel, IN HANDLE Event)
NTSTATUS NTAPI | RtlSetThreadPoolStartFunc (PRTLP_START_THREAD StartFunc, PRTLP_EXIT_THREAD ExitFunc)
NTSTATUS | RtlThreadPoolCleanup (ULONG Flags)
NTSTATUS | RtlpQueueWorkerRequest (WORKERCALLBACKFUNC Function, PVOID Context, ULONG Flags)
VOID | RtlpExecuteWorkerRequest (NTSTATUS Status, PVOID Context, PVOID WorkContext)
NTSTATUS | RtlpQueueIOWorkerRequest (WORKERCALLBACKFUNC Function, PVOID Context, ULONG Flags)
NTSTATUS | RtlpStartWorkerThread ()
NTSTATUS | RtlpStartIOWorkerThread ()
VOID | RtlpWorkerThreadTimerCallback (PVOID Context, BOOLEAN NotUsed)
NTSTATUS | RtlpInitializeWorkerThreadPool ()
VOID | RtlpWorkerThreadInitializeTimers (PVOID Context)
LONG | RtlpWorkerThread (PVOID Initialized)
LONG | RtlpIOWorkerThread (PVOID Initialized)
VOID | RtlpExecuteLongIOWorkItem (PVOID Function, PVOID Context, PVOID ThreadCB)
VOID | RtlpExecuteIOWorkItem (PVOID Function, PVOID Context, PVOID NotUsed)
NTSTATUS NTAPI | RtlpStartThread (PUSER_THREAD_START_ROUTINE Function, HANDLE *ThreadHandle)
NTSTATUS | RtlpExitThread (NTSTATUS Status)
NTSTATUS | RtlpInitializeWaitThreadPool ()
LONG | RtlpWaitThread (PVOID Initialized)
VOID | RtlpAsyncCallbackCompletion (PVOID Context)
VOID | RtlpProcessWaitCompletion (PRTLP_WAIT Wait, ULONG ArrayIndex)
VOID | RtlpAddWait (PRTLP_WAIT Wait)
NTSTATUS | RtlpDeregisterWait (PRTLP_WAIT Wait, HANDLE PartialCompletionEvent, PULONG RetStatusPtr)
NTSTATUS | RtlpDeactivateWait (PRTLP_WAIT Wait)
VOID | RtlpDeleteWait (PRTLP_WAIT Wait)
VOID | RtlpDoNothing (PVOID NotUsed1, PVOID NotUsed2, PVOID NotUsed3)
__inline LONGLONG | RtlpGet64BitTickCount (LARGE_INTEGER *Last64BitTickCount)
__inline LONGLONG | RtlpResync64BitTickCount ()
VOID | RtlpProcessTimeouts (PRTLP_WAIT_THREAD_CONTROL_BLOCK ThreadCB)
VOID | RtlpFireTimers (PLIST_ENTRY TimersToFireList)
NTSTATUS | RtlpFindWaitThread (PRTLP_WAIT_THREAD_CONTROL_BLOCK *ThreadCB)
VOID | RtlpAddTimer (PRTLP_TIMER Timer)
VOID | RtlpUpdateTimer (PRTLP_TIMER Timer, PRTLP_TIMER UpdatedTimer)
VOID | RtlpCancelTimer (PRTLP_TIMER Timer)
VOID | RtlpCancelTimerEx (PRTLP_TIMER Timer, BOOLEAN DeletingQueue)
VOID | RtlpDeactivateTimer (PRTLP_TIMER_QUEUE Queue, PRTLP_TIMER Timer)
VOID | RtlpDeleteTimer (PRTLP_TIMER Timer)
ULONG | RtlpGetQueueRelativeTime (PRTLP_TIMER_QUEUE Queue)
ULONG | RtlpGetTimeRemaining (HANDLE TimerHandle)
VOID | RtlpResetTimer (HANDLE TimerHandle, ULONG DueTime, PRTLP_WAIT_THREAD_CONTROL_BLOCK ThreadCB)
BOOLEAN | RtlpInsertInDeltaList (PLIST_ENTRY DeltaList, PRTLP_GENERIC_TIMER NewTimer, ULONG TimeRemaining, ULONG *NewFiringTime)
BOOLEAN | RtlpRemoveFromDeltaList (PLIST_ENTRY DeltaList, PRTLP_GENERIC_TIMER Timer, ULONG TimeRemaining, ULONG *NewFiringTime)
BOOLEAN | RtlpReOrderDeltaList (PLIST_ENTRY DeltaList, PRTLP_GENERIC_TIMER Timer, ULONG TimeRemaining, ULONG *NewFiringTime, ULONG ChangedFiringTime)
VOID | RtlpAddTimerQueue (PVOID Queue)
VOID | RtlpServiceTimer (PVOID NotUsedArg, ULONG NotUsedLowTimer, LONG NotUsedHighTimer)
VOID | RtlpFireTimersAndReorder (PRTLP_TIMER_QUEUE Queue, ULONG *NewFiringTime, PLIST_ENTRY TimersToFireList)
VOID | RtlpInsertTimersIntoDeltaList (IN PLIST_ENTRY NewTimerList, IN PLIST_ENTRY DeltaTimerList, IN ULONG TimeRemaining, OUT ULONG *NewFiringTime)
LONG | RtlpTimerThread (PVOID Initialized)
NTSTATUS | RtlpInitializeTimerThreadPool ()
NTSTATUS | RtlpDeleteTimerQueue (PRTLP_TIMER_QUEUE Queue)
VOID | RtlpDeleteTimerQueueComplete (PRTLP_TIMER_QUEUE Queue)
VOID | RtlpThreadCleanup ()
NTSTATUS | RtlpWaitForEvent (HANDLE Event, HANDLE ThreadHandle)
PRTLP_EVENT | RtlpGetWaitEvent (VOID)
VOID | RtlpFreeWaitEvent (PRTLP_EVENT Event)
VOID | RtlpInitializeEventCache (VOID)
VOID | PrintTimerQueue (PLIST_ENTRY QNode, ULONG Delta, ULONG Count)
VOID | RtlDebugPrintTimes ()
NTSTATUS | RtlSetTimer (IN HANDLE TimerQueueHandle, OUT HANDLE *Handle, IN WAITORTIMERCALLBACKFUNC Function, IN PVOID Context, IN ULONG DueTime, IN ULONG Period, IN ULONG Flags)
PVOID | RtlpForceAllocateTPHeap (ULONG dwSize, ULONG dwFlags)
NTSTATUS | RtlCancelTimer (IN HANDLE TimerQueueHandle, IN HANDLE TimerToCancel)

## Variables

ULONG | DPRN = 0x0000000

## Define Documentation

#define IOWORKER_IDLE_TIMEOUT 40000

| Referenced by RtlpIOWorkerThread().

#define MAX_WORKER_SLEEP_TIME_EXPONENT 4

| Referenced by RtlpWorkerThread().

#define WAIT_IDLE_TIMEOUT 400000

| Referenced by RtlpWaitThread().

#define WORKER_IDLE_TIMEOUT 40000

| Referenced by RtlpWorkerThread().

## Function Documentation

VOID PrintTimerQueue | ( | PLIST_ENTRY | QNode,
|  | ULONG | Delta,
|  | ULONG | Count
| ) |

Definition at line 5745 of file threads.c.

References Count, DbgPrint, List, PRTLP_TIMER, PRTLP_TIMER_QUEUE, RTLP_TIMER, and RTLP_TIMER_QUEUE.

Referenced by RtlDebugPrintTimes().

    05747 {
    05748     PLIST_ENTRY Tnode ;
    05749     PRTLP_TIMER Timer ;
    05750     PRTLP_TIMER_QUEUE Queue ;
    05751
    05752     Queue = CONTAINING_RECORD (QNode, RTLP_TIMER_QUEUE, List) ;
    05753     DbgPrint("<%1d> Queue: %x FiringTime:%d\n", Count, (ULONG_PTR)Queue,
    05754                 Queue->DeltaFiringTime);
    05755     for (Tnode=Queue->TimerList.Flink; Tnode!=&Queue->TimerList;
    05756             Tnode=Tnode->Flink)
    05757     {
    05758         Timer = CONTAINING_RECORD (Tnode, RTLP_TIMER, List) ;
    05759         Delta += Timer->DeltaFiringTime ;
    05760         DbgPrint("        Timer: %x Delta:%d Period:%d\n",(ULONG_PTR)Timer,
    05761                     Delta, Timer->Period);
    05762     }
    05763
    05764 }

NTSTATUS RtlCancelTimer | ( | IN HANDLE | TimerQueueHandle,
|  | IN HANDLE | TimerToCancel
| ) |

Definition at line 5895 of file threads.c.

References Count, DbgPrint, NULL, and RtlDeleteTimer().

    05901                    :
    05902
    05903     This routine cancels the timer. This call is non-blocking. The timer Callback
    05904     will not be executed after this call returns.
    05905
    05906 Arguments:
    05907
    05908     TimerQueueHandle - Handle identifying the queue from which to delete timer
    05909
    05910     TimerToCancel - Handle identifying the timer to cancel
    05911
    05912 Return Value:
    05913
    05914     NTSTATUS - Result code from call.  The following are returned
    05915
    05916         STATUS_SUCCESS - Timer cancelled. All callbacks completed.
    05917         STATUS_PENDING - Timer cancelled. Some callbacks still not completed.
    05918
    05919 --*/
    05920 {
    05921     static ULONG Count = 0;
    05922     if (Count++ ==0) {
    05923         DbgPrint("Using obsolete function call: RtlCancelTimer\n");
    05924         DbgBreakPoint();
    05925         DbgPrint("Using obsolete function call: RtlCancelTimer\n");
    05926     }
    05927
    05928     return RtlDeleteTimer( TimerQueueHandle, TimerToCancel, NULL ) ;
    05929 }

NTSTATUS RtlCreateTimer | ( | IN HANDLE | TimerQueueHandle,
|  | OUT HANDLE * | Handle,
|  | IN WAITORTIMERCALLBACKFUNC | Function,
|  | IN PVOID | Context,
|  | IN ULONG | DueTime,
|  | IN ULONG | Period,
|  | IN ULONG | Flags
| ) |

Definition at line 944 of file threads.c.

References DbgPrint, DPRN1, Handle, NtQueueApcThread(), NTSTATUS(), NULL, PRTLP_TIMER, PRTLP_TIMER_QUEUE, RefCount, RTLP_TIMER, RtlpAddTimer(), RtlpAllocateTPHeap, SET_SIGNATURE, Status, and TimerThreadHandle.

Referenced by RtlpWorkerThreadInitializeTimers(), and RtlSetTimer().

    00955                    :
    00956
    00957     This routine puts a timer request in the queue identified in by TimerQueueHandle.
    00958     The timer request can be one shot or periodic.
    00959
    00960 Arguments:
    00961
    00962     TimerQueueHandle - Handle identifying the timer queue in which to insert the timer
    00963                     request.
    00964
    00965     Handle - Specifies a location to return a handle to this timer request
    00966
    00967     Function - Routine that is called when the timer fires
    00968
    00969     Context - Opaque pointer passed in as an argument to WorkerProc
    00970
    00971     DueTime - Specifies the time in milliseconds after which the timer fires.
    00972
    00973     Period - Specifies the period of the timer in milliseconds. This should be 0 for
    00974     one shot requests.
    00975
    00976     Flags - Can be one of:
    00977
    00978             WT_EXECUTEINTIMERTHREAD - if WorkerProc should be invoked in the wait thread
    00979             it this should only be used for small routines.
    00980
    00981             WT_EXECUTELONGFUNCTION - if WorkerProc can possibly block for a long time.
    00982
    00983             WT_EXECUTEINIOTHREAD - if WorkerProc should be invoked in IO worker thread
    00984
    00985 Return Value:
    00986
    00987     NTSTATUS - Result code from call.  The following are returned
    00988
    00989         STATUS_SUCCESS - Timer Queue created successfully.
    00990
    00991         STATUS_NO_MEMORY - There was not sufficient heap to perform the
    00992             requested operation.
    00993
    00994 --*/
    00995
    00996 {
    00997     NTSTATUS Status;
    00998     PRTLP_TIMER Timer ;
    00999
    01000     Timer = (PRTLP_TIMER) RtlpAllocateTPHeap (
    01001                                 sizeof (RTLP_TIMER),
    01002                                 HEAP_ZERO_MEMORY
    01003                                 ) ;
    01004
    01005     if (Timer == NULL) {
    01006
    01007         return STATUS_NO_MEMORY ;
    01008
    01009     }
    01010
    01011     // Initialize the allocated timer
    01012
    01013     Timer->DeltaFiringTime = DueTime ;
    01014     Timer->Queue = (PRTLP_TIMER_QUEUE) TimerQueueHandle ;
    01015     Timer->RefCount = 1 ;
    01016     Timer->Flags = Flags ;
    01017     Timer->Function = Function ;
    01018     Timer->Context = Context ;
    01019     //todo:remove below
    01020     Timer->Period = (Period == -1) ? 0 : Period;
    01021     InitializeListHead( &Timer->TimersToFireList ) ;
    01022     SET_SIGNATURE( Timer ) ;
    01023
    01024
    01025     #if DBG1
    01026     Timer->DbgId = ++ Timer->Queue->NextDbgId ;
    01027     Timer->ThreadId = HandleToUlong(NtCurrentTeb()->ClientId.UniqueThread) ;
    01028     if (DPRN1)
    01029     DbgPrint("\n<%d:%d:%d> Timer: created by Thread:<%x:%x>\n\n",
    01030             Timer->Queue->DbgId, Timer->DbgId, 1,
    01031             HandleToUlong(NtCurrentTeb()->ClientId.UniqueThread),
    01032             HandleToUlong(NtCurrentTeb()->ClientId.UniqueProcess)) ;
    01033     #endif
    01034
    01035     *Handle = Timer ;
    01036
    01037
    01038     // Increment the total number of timers in the queue
    01039
    01040     InterlockedIncrement( &((PRTLP_TIMER_QUEUE)TimerQueueHandle)->RefCount ) ;
    01041
    01042
    01043     // Queue APC to timer thread
    01044
    01045     Status = NtQueueApcThread(
    01046                     TimerThreadHandle,
    01047                     (PPS_APC_ROUTINE)RtlpAddTimer,
    01048                     (PVOID)Timer,
    01049                     NULL,
    01050                     NULL
    01051                     ) ;
    01052
    01053     return Status ;
    01054 }

NTSTATUS RtlCreateTimerQueue | ( | OUT PHANDLE | TimerQueueHandle | ) |

Definition at line 691 of file threads.c.

References CompletedTimerInitialization, DbgPrint, DPRN0, NextTimerDbgId, NT_SUCCESS, NTSTATUS(), NULL, NumTimerQueues, PRTLP_TIMER_QUEUE, RTLP_TIMER_QUEUE, RtlpAllocateTPHeap, RtlpInitializeTimerThreadPool(), SET_SIGNATURE, and Status.

Referenced by RtlpWorkerThreadInitializeTimers().

    00697                    :
    00698
    00699     This routine creates a queue that can be used to queue time based tasks.
    00700
    00701 Arguments:
    00702
    00703     TimerQueueHandle - Returns back the Handle identifying the timer queue created.
    00704
    00705 Return Value:
    00706
    00707     NTSTATUS - Result code from call.  The following are returned
    00708
    00709         STATUS_SUCCESS - Timer Queue created successfully.
    00710
    00711         STATUS_NO_MEMORY - There was not sufficient heap to perform the
    00712             requested operation.
    00713
    00714 --*/
    00715
    00716 {
    00717     PRTLP_TIMER_QUEUE Queue ;
    00718     NTSTATUS Status;
    00719
    00720
    00721     // Initialize the timer component if it hasnt been done already
    00722
    00723     if (CompletedTimerInitialization != 1) {
    00724
    00725         Status = RtlpInitializeTimerThreadPool () ;
    00726
    00727         if ( !NT_SUCCESS(Status) )
    00728             return Status ;
    00729
    00730     }
    00731
    00732
    00733     InterlockedIncrement( &NumTimerQueues ) ;
    00734
    00735
    00736     // Allocate a Queue structure
    00737
    00738     Queue = (PRTLP_TIMER_QUEUE) RtlpAllocateTPHeap (
    00739                                       sizeof (RTLP_TIMER_QUEUE),
    00740                                       HEAP_ZERO_MEMORY
    00741                                       ) ;
    00742
    00743     if (Queue == NULL) {
    00744
    00745         InterlockedDecrement( &NumTimerQueues ) ;
    00746
    00747         return STATUS_NO_MEMORY ;
    00748     }
    00749
    00750     Queue->RefCount = 1 ;
    00751
    00752
    00753     // Initialize the allocated queue
    00754
    00755     InitializeListHead (&Queue->List) ;
    00756     InitializeListHead (&Queue->TimerList) ;
    00757     InitializeListHead (&Queue->UncancelledTimerList) ;
    00758     SET_SIGNATURE( Queue ) ;
    00759
    00760     Queue->DeltaFiringTime = 0 ;
    00761
    00762     #if DBG1
    00763     Queue->DbgId = ++NextTimerDbgId ;
    00764     Queue->ThreadId = HandleToUlong(NtCurrentTeb()->ClientId.UniqueThread) ;
    00765     if (DPRN0)
    00766     DbgPrint("<%d:%d> TimerQueue %x created by thread:<%x:%x>\n\n",
    00767                 Queue->DbgId, 1, (ULONG_PTR)Queue,
    00768                 HandleToUlong(NtCurrentTeb()->ClientId.UniqueThread),
    00769                 HandleToUlong(NtCurrentTeb()->ClientId.UniqueProcess)) ;
    00770     #endif
    00771
    00772     *TimerQueueHandle = Queue ;
    00773
    00774     return STATUS_SUCCESS ;
    00775 }

VOID RtlDebugPrintTimes | ( |  | ) |

Definition at line 5767 of file threads.c.

References CompletedTimerInitialization, Count, DbgPrint, List, NtQueueApcThread(), NULL, PrintTimerQueue(), PRTLP_TIMER_QUEUE, RtlDebugPrintTimes(), RTLP_TIMER_QUEUE, RtlpGetTimeRemaining(), RtlpResync64BitTickCount(), TimerHandle, TimerQueues, TimerThreadHandle, and TimerThreadId.

Referenced by RtlDebugPrintTimes(), and RtlpServiceTimer().

    05769 {
    05770     PLIST_ENTRY QNode ;
    05771     ULONG Count = 0 ;
    05772     ULONG Delta = RtlpGetTimeRemaining (TimerHandle) ;
    05773     ULONG CurrentThreadId =
    05774                         HandleToUlong(NtCurrentTeb()->ClientId.UniqueThread) ;
    05775
    05776     RtlpResync64BitTickCount();
    05777
    05778     if (CompletedTimerInitialization != 1) {
    05779
    05780         DbgPrint("===========RtlTimerThread not yet initialized==========\n");
    05781         return ;
    05782     }
    05783
    05784     if (CurrentThreadId == TimerThreadId)
    05785     {
    05786         PRTLP_TIMER_QUEUE Queue ;
    05787
    05788         DbgPrint("================Printing timerqueues====================\n");
    05789         DbgPrint("TimeRemaining: %d\n", Delta);
    05790         for (QNode = TimerQueues.Flink; QNode != &TimerQueues;
    05791                 QNode = QNode->Flink)
    05792         {
    05793             Queue = CONTAINING_RECORD (QNode, RTLP_TIMER_QUEUE, List) ;
    05794             Delta += Queue->DeltaFiringTime ;
    05795
    05796             PrintTimerQueue(QNode, Delta, ++Count);
    05797
    05798         }
    05799         DbgPrint("================Printed ================================\n");
    05800     }
    05801
    05802     else
    05803     {
    05804         NtQueueApcThread(
    05805                     TimerThreadHandle,
    05806                     (PPS_APC_ROUTINE)RtlDebugPrintTimes,
    05807                     NULL,
    05808                     NULL,
    05809                     NULL
    05810                     );
    05811     }
    05812 }

NTSTATUS RtlDeleteTimer | ( | IN HANDLE | TimerQueueHandle,
|  | IN HANDLE | TimerToCancel,
|  | IN HANDLE | Event
| ) |

Definition at line 1145 of file threads.c.

References ACQUIRE_GLOBAL_TIMER_LOCK, ASSERT, CHECK_DEL_SIGNATURE, DbgPrint, DPRN0, Event(), FALSE, _RTLP_EVENT::Handle, NT_SUCCESS, NtQueueApcThread(), NTSTATUS(), NULL, PRTLP_TIMER, PRTLP_TIMER_QUEUE, RELEASE_GLOBAL_TIMER_LOCK, RtlpCancelTimer(), RtlpFreeWaitEvent(), RtlpGetWaitEvent(), RtlpWaitForEvent(), SET_DEL_SIGNATURE, STATE_DONTFIRE, Status, and TimerThreadHandle.

Referenced by RtlCancelTimer().

    01152                    :
    01153
    01154     This routine cancels the timer
    01155
    01156 Arguments:
    01157
    01158     TimerQueueHandle - Handle identifying the queue from which to delete timer
    01159
    01160     TimerToCancel - Handle identifying the timer to cancel
    01161
    01162     Event - Event to be signalled when the timer is deleted
    01163             (HANDLE)-1: The function creates an event and waits on it.
    01164             Event : The caller passes an event. The function marks the timer for deletion,
    01165                     but does not wait for all callbacks to complete. The event is
    01166                     signalled after all callbacks have completed.
    01167             NULL : The function is non-blocking. The function marks the timer for deletion,
    01168                     but does not wait for all callbacks to complete.
    01169
    01170 Return Value:
    01171
    01172     NTSTATUS - Result code from call.  The following are returned
    01173
    01174         STATUS_SUCCESS - Timer cancelled. No pending callbacks.
    01175         STATUS_PENDING - Timer cancelled. Some callbacks still not completed.
    01176
    01177 --*/
    01178 {
    01179     NTSTATUS Status;
    01180     PRTLP_EVENT CompletionEvent = NULL ;
    01181     PRTLP_TIMER Timer = (PRTLP_TIMER) TimerToCancel ;
    01182     ULONG TimerRefCount ;
    01183     #if DBG1
    01184     ULONG QueueDbgId ;
    01185     #endif
    01186
    01187
    01188     if (!TimerQueueHandle || !TimerToCancel) {
    01189         ASSERT( FALSE ) ;
    01190         return STATUS_INVALID_PARAMETER ;
    01191     }
    01192
    01193     #if DBG1
    01194     QueueDbgId = Timer->Queue->DbgId ;
    01195     #endif
    01196
    01197
    01198     CHECK_DEL_SIGNATURE( Timer ) ;
    01199     SET_DEL_SIGNATURE( Timer ) ;
    01200     CHECK_DEL_SIGNATURE( (PRTLP_TIMER_QUEUE)TimerQueueHandle ) ;
    01201
    01202
    01203     if (Event == (HANDLE)-1 ) {
    01204
    01205         // Get an event from the event cache
    01206
    01207         CompletionEvent = RtlpGetWaitEvent () ;
    01208
    01209         if (!CompletionEvent) {
    01210
    01211             return STATUS_NO_MEMORY ;
    01212         }
    01213     }
    01214
    01215     #if DBG1
    01216     Timer->ThreadId2 = HandleToUlong(NtCurrentTeb()->ClientId.UniqueThread) ;
    01217     #endif
    01218     #if DBG1
    01219     if (DPRN0)
    01220     DbgPrint("\n<%d:%d:%d> Timer: Cancel:(Timer:%x, Event:%x)\n\n",
    01221                 Timer->Queue->DbgId, Timer->DbgId, Timer->RefCount,
    01222                 (ULONG_PTR)Timer, (ULONG_PTR)Event) ;
    01223     #endif
    01224
    01225     Timer->CompletionEvent = CompletionEvent
    01226                             ? CompletionEvent->Handle
    01227                             : Event ;
    01228
    01229
    01230     ACQUIRE_GLOBAL_TIMER_LOCK();
    01231     Timer->State |= STATE_DONTFIRE ;
    01232     TimerRefCount = Timer->RefCount ;
    01233     RELEASE_GLOBAL_TIMER_LOCK();
    01234
    01235
    01236     Status = NtQueueApcThread(
    01237                 TimerThreadHandle,
    01238                 (PPS_APC_ROUTINE)RtlpCancelTimer,
    01239                 (PVOID)TimerToCancel,
    01240                 NULL,
    01241                 NULL
    01242                 );
    01243
    01244     if (! NT_SUCCESS(Status)) {
    01245
    01246         RtlpFreeWaitEvent( CompletionEvent ) ;
    01247
    01248         return Status ;
    01249     }
    01250
    01251
    01252
    01253     if ( CompletionEvent ) {
    01254
    01255         // wait for the event to be signalled
    01256
    01257         #if DBG1
    01258         if (DPRN0)
    01259         DbgPrint("<%d> Timer: %x: Cancel waiting Thread<%d:%d>\n\n",
    01260                 QueueDbgId, (ULONG_PTR)Timer,
    01261                 HandleToUlong(NtCurrentTeb()->ClientId.UniqueThread),
    01262                 HandleToUlong(NtCurrentTeb()->ClientId.UniqueProcess)) ;
    01263         #endif
    01264
    01265
    01266         Status = RtlpWaitForEvent( CompletionEvent->Handle,  TimerThreadHandle ) ;
    01267
    01268
    01269         #if DBG1
    01270         if (DPRN0)
    01271         DbgPrint("<%d> Timer: %x: Cancel waiting done\n\n", QueueDbgId,
    01272                 (ULONG_PTR)Timer) ;
    01273         #endif
    01274
    01275
    01276         RtlpFreeWaitEvent( CompletionEvent ) ;
    01277
    01278         return NT_SUCCESS(Status) ? STATUS_SUCCESS : Status ;
    01279
    01280     } else {
    01281
    01282         return (TimerRefCount > 1) ? STATUS_PENDING : STATUS_SUCCESS;
    01283     }
    01284 }

NTSTATUS RtlDeleteTimerQueue | ( | IN HANDLE | TimerQueueHandle | ) |

Definition at line 779 of file threads.c.

References NULL, and RtlDeleteTimerQueueEx().

    00785                    :
    00786
    00787     This routine deletes a previously created queue. This call is non-blocking and
    00788     can be made from Callbacks. Pending callbacks already queued to worker threads
    00789     are not cancelled.
    00790
    00791 Arguments:
    00792
    00793     TimerQueueHandle - Handle identifying the timer queue created.
    00794
    00795 Return Value:
    00796
    00797     NTSTATUS - Result code from call.
    00798
    00799         STATUS_PENDING - Timer Queue created successfully.
    00800
    00801 --*/
    00802
    00803 {
    00804     return RtlDeleteTimerQueueEx( TimerQueueHandle, NULL ) ;
    00805 }

NTSTATUS RtlDeleteTimerQueueEx | ( | HANDLE | QueueHandle,
|  | HANDLE | Event
| ) |

Definition at line 809 of file threads.c.

References ACQUIRE_GLOBAL_TIMER_LOCK, ASSERT, CHECK_DEL_SIGNATURE, DbgPrint, DPRN0, Event(), FALSE, _RTLP_EVENT::Handle, NT_SUCCESS, NtQueueApcThread(), NTSTATUS(), NULL, PRTLP_TIMER_QUEUE, RELEASE_GLOBAL_TIMER_LOCK, RtlpDeleteTimerQueue(), RtlpFreeWaitEvent(), RtlpGetWaitEvent(), RtlpWaitForEvent(), SET_DEL_SIGNATURE, STATE_DONTFIRE, Status, and TimerThreadHandle.

Referenced by RtlDeleteTimerQueue().

    00815                    :
    00816
    00817     This routine deletes the queue specified in the Request and frees all timers.
    00818     This call is blocking or non-blocking depending on the value passed for Event.
    00819     Blocking calls cannot be made from ANY Timer callbacks. After this call returns,
    00820     no new Callbacks will be fired for any timer associated with the queue.
    00821
    00822 Arguments:
    00823
    00824     QueueHandle - queue to delete
    00825
    00826     Event - Event to wait upon.
    00827             (HANDLE)-1: The function creates an event and waits on it.
    00828             Event : The caller passes an event. The function marks the queue for deletion,
    00829                     but does not wait for all callbacks to complete. The event is
    00830                     signalled after all callbacks have completed.
    00831             NULL : The function is non-blocking. The function marks the queue for deletion,
    00832                     but does not wait for all callbacks to complete.
    00833
    00834 Return Value:
    00835
    00836     STATUS_SUCCESS - All timer callbacks have completed.
    00837     STATUS_PENDING - Non-Blocking call. Some timer callbacks associated with timers
    00838                     in this queue may not have completed.
    00839
    00840 --*/
    00841 {
    00842     NTSTATUS Status;
    00843     LARGE_INTEGER TimeOut ;
    00844     PRTLP_EVENT CompletionEvent = NULL ;
    00845     PRTLP_TIMER_QUEUE Queue = (PRTLP_TIMER_QUEUE)QueueHandle ;
    00846
    00847     if (!Queue) {
    00848         ASSERT( FALSE ) ;
    00849         return STATUS_INVALID_PARAMETER ;
    00850     }
    00851
    00852     CHECK_DEL_SIGNATURE( Queue ) ;
    00853     SET_DEL_SIGNATURE( Queue ) ;
    00854
    00855
    00856     #if DBG1
    00857     Queue->ThreadId2 = HandleToUlong(NtCurrentTeb()->ClientId.UniqueThread) ;
    00858     if (DPRN0)
    00859     DbgPrint("\n<%d:%d> Queue Delete(Queue:%x Event:%x by Thread:<%x:%x>)\n\n",
    00860              Queue->DbgId, Queue->RefCount, (ULONG_PTR)Queue, (ULONG_PTR)Event,
    00861              HandleToUlong(NtCurrentTeb()->ClientId.UniqueThread),
    00862              HandleToUlong(NtCurrentTeb()->ClientId.UniqueProcess)) ;
    00863     #endif
    00864
    00865
    00866     if (Event == (HANDLE)-1 ) {
    00867
    00868         // Get an event from the event cache
    00869
    00870         CompletionEvent = RtlpGetWaitEvent () ;
    00871
    00872         if (!CompletionEvent) {
    00873
    00874             return STATUS_NO_MEMORY ;
    00875
    00876         }
    00877     }
    00878
    00879     Queue->CompletionEvent = CompletionEvent
    00880                              ? CompletionEvent->Handle
    00881                              : Event ;
    00882
    00883
    00884     // once this flag is set, no timer will be fired
    00885
    00886     ACQUIRE_GLOBAL_TIMER_LOCK();
    00887     Queue->State |= STATE_DONTFIRE;
    00888     RELEASE_GLOBAL_TIMER_LOCK();
    00889
    00890
    00891
    00892     // queue an APC
    00893
    00894     Status = NtQueueApcThread(
    00895                     TimerThreadHandle,
    00896                     (PPS_APC_ROUTINE)RtlpDeleteTimerQueue,
    00897                     (PVOID) QueueHandle,
    00898                     NULL,
    00899                     NULL
    00900                     );
    00901
    00902     if (! NT_SUCCESS(Status)) {
    00903
    00904         RtlpFreeWaitEvent( CompletionEvent ) ;
    00905
    00906         return Status ;
    00907     }
    00908
    00909     if (CompletionEvent) {
    00910
    00911         // wait for Event to be fired. Return if the thread has been killed.
    00912
    00913
    00914         #if DBG1
    00915         if (DPRN0)
    00916         DbgPrint("<%x> Queue delete waiting Thread<%d:%d>\n\n",
    00917                 (ULONG_PTR)Queue,
    00918                 HandleToUlong(NtCurrentTeb()->ClientId.UniqueThread),
    00919                 HandleToUlong(NtCurrentTeb()->ClientId.UniqueProcess)) ;
    00920         #endif
    00921
    00922
    00923         Status = RtlpWaitForEvent( CompletionEvent->Handle, TimerThreadHandle ) ;
    00924
    00925
    00926         #if DBG1
    00927         if (DPRN0)
    00928         DbgPrint("<%x> Queue delete completed\n\n", (ULONG_PTR) Queue) ;
    00929         #endif
    00930
    00931         RtlpFreeWaitEvent( CompletionEvent ) ;
    00932
    00933         return NT_SUCCESS( Status ) ? STATUS_SUCCESS : Status ;
    00934
    00935     } else {
    00936
    00937         return STATUS_PENDING ;
    00938     }
    00939 }

NTSTATUS RtlDeregisterWait | ( | IN HANDLE | WaitHandle | ) |

Definition at line 228 of file threads.c.

References NULL, and RtlDeregisterWaitEx().

Referenced by RtlShutdownLpcServer().

    00233                    :
    00234
    00235     This routine removes the specified wait from the pool of objects being
    00236     waited on. This routine is non-blocking. Once this call returns, no new
    00237     Callbacks are invoked. However, Callbacks that might already have been queued
    00238     to worker threads are not cancelled.
    00239
    00240 Arguments:
    00241
    00242     WaitHandle - Handle indentifying the wait.
    00243
    00244 Return Value:
    00245
    00246     STATUS_SUCCESS - The deregistration was successful.
    00247     STATUS_PENDING - Some callbacks associated with this Wait, are still executing.
    00248 --*/
    00249
    00250 {
    00251     return RtlDeregisterWaitEx( WaitHandle, NULL ) ;
    00252 }

NTSTATUS RtlDeregisterWaitEx | ( | IN HANDLE | WaitHandle,
|  | IN HANDLE | Event
| ) |

Definition at line 256 of file threads.c.

References ASSERT, CHECK_DEL_SIGNATURE, _RTLP_WAIT::DbgId, DbgPrint, DPRN0, Event(), FALSE, _RTLP_EVENT::Handle, NT_SUCCESS, NtQueueApcThread(), NTSTATUS(), NULL, _RTLP_WAIT::RefCount, RtlpDeregisterWait(), RtlpFreeWaitEvent(), RtlpGetWaitEvent(), RtlpWaitForEvent(), SET_DEL_SIGNATURE, Status, _RTLP_WAIT::ThreadCB, _RTLP_WAIT_THREAD_CONTROL_BLOCK::ThreadHandle, ThreadHandle, and _RTLP_WAIT::ThreadId2.

Referenced by RtlDeregisterWait().

    00262                    :
    00263
    00264     This routine removes the specified wait from the pool of objects being
    00265     waited on. Once this call returns, no new Callbacks will be invoked.
    00266     Depending on the value of Event, the call can be blocking or non-blocking.
    00267     Blocking calls MUST NOT be invoked inside the callback routines, except
    00268     when a callback being executed in the Wait thread context deregisters
    00269     its associated Wait (in this case there is no reason for making blocking calls),
    00270     or when a callback queued to a worker thread is deregistering some other wait item
    00271     (be careful of deadlocks here).
    00272
    00273 Arguments:
    00274
    00275     WaitHandle - Handle indentifying the wait.
    00276
    00277     Event - Event to wait upon.
    00278             (HANDLE)-1: The function creates an event and waits on it.
    00279             Event : The caller passes an Event. The function removes the wait handle,
    00280                     but does not wait for all callbacks to complete. The Event is
    00281                     released after all callbacks have completed.
    00282             NULL : The function is non-blocking. The function removes the wait handle,
    00283                     but does not wait for all callbacks to complete.
    00284
    00285 Return Value:
    00286
    00287     STATUS_SUCCESS - The deregistration was successful.
    00288     STATUS_PENDING - Some callback is still pending.
    00289
    00290 --*/
    00291
    00292 {
    00293     NTSTATUS Status, StatusAsync = STATUS_SUCCESS ;
    00294     PRTLP_WAIT Wait = (PRTLP_WAIT) WaitHandle ;
    00295     ULONG CurrentThreadId =  HandleToUlong(NtCurrentTeb()->ClientId.UniqueThread) ;
    00296     PRTLP_EVENT CompletionEvent = NULL ;
    00297     HANDLE ThreadHandle ;
    00298     ULONG NonBlocking = ( Event != (HANDLE) -1 ) ; //The call returns non-blocking
    00299
    00300
    00301     if (!Wait) {
    00302         ASSERT( FALSE ) ;
    00303         return STATUS_INVALID_PARAMETER ;
    00304     }
    00305
    00306     ThreadHandle = Wait->ThreadCB->ThreadHandle ;
    00307
    00308
    00309     CHECK_DEL_SIGNATURE( Wait ) ;
    00310     SET_DEL_SIGNATURE( Wait ) ;
    00311
    00312     #if DBG1
    00313     Wait->ThreadId2 = CurrentThreadId ;
    00314     #endif
    00315
    00316     if (Event == (HANDLE)-1) {
    00317
    00318         // Get an event from the event cache
    00319
    00320         CompletionEvent = RtlpGetWaitEvent () ;
    00321
    00322         if (!CompletionEvent) {
    00323
    00324             return STATUS_NO_MEMORY ;
    00325
    00326         }
    00327     }
    00328
    00329
    00330     Wait = (PRTLP_WAIT) WaitHandle ;
    00331
    00332     #if DBG1
    00333     if (DPRN0)
    00334     DbgPrint("<%d:%d> Wait %x deregistering by thread:<%x:%x>\n\n", Wait->DbgId,
    00335                 Wait->RefCount, (ULONG_PTR)Wait,
    00336                 CurrentThreadId,
    00337                 HandleToUlong(NtCurrentTeb()->ClientId.UniqueProcess)) ;
    00338     #endif
    00339
    00340
    00341     Wait->CompletionEvent = CompletionEvent
    00342                             ? CompletionEvent->Handle
    00343                             : Event ;
    00344
    00345     //
    00346     // RtlDeregisterWaitEx is being called from within the Wait thread callback
    00347     //
    00348
    00349     if ( CurrentThreadId == Wait->ThreadCB->ThreadId ) {
    00350
    00351         Status = RtlpDeregisterWait ( Wait, NULL, NULL ) ;
    00352
    00353
    00354         // all callback functions run in the wait thread. So cannot return PENDING
    00355
    00356         ASSERT ( Status != STATUS_PENDING ) ;
    00357
    00358
    00359     } else {
    00360
    00361         PRTLP_EVENT PartialCompletionEvent = NULL ;
    00362
    00363         if (NonBlocking) {
    00364
    00365             PartialCompletionEvent = RtlpGetWaitEvent () ;
    00366
    00367             if (!PartialCompletionEvent) {
    00368
    00369                 return STATUS_NO_MEMORY ;
    00370             }
    00371         }
    00372
    00373         // Queue an APC to the Wait Thread
    00374
    00375         Status = NtQueueApcThread(
    00376                         Wait->ThreadCB->ThreadHandle,
    00377                         (PPS_APC_ROUTINE)RtlpDeregisterWait,
    00378                         (PVOID) Wait,
    00379                         NonBlocking ? PartialCompletionEvent->Handle : NULL ,
    00380                         NonBlocking ? (PVOID)&StatusAsync : NULL
    00381                         );
    00382
    00383         if (! NT_SUCCESS(Status)) {
    00384
    00385             if (CompletionEvent) RtlpFreeWaitEvent( CompletionEvent ) ;
    00386             if (PartialCompletionEvent) RtlpFreeWaitEvent( PartialCompletionEvent ) ;
    00387
    00388             return Status ;
    00389         }
    00390
    00391
    00392         // block till the wait entry has been deactivated
    00393
    00394         if (NonBlocking) {
    00395
    00396             Status = RtlpWaitForEvent( PartialCompletionEvent->Handle, ThreadHandle ) ;
    00397         }
    00398
    00399
    00400         if (PartialCompletionEvent) RtlpFreeWaitEvent( PartialCompletionEvent ) ;
    00401
    00402     }
    00403
    00404     if ( CompletionEvent ) {
    00405
    00406         // wait for Event to be fired. Return if the thread has been killed.
    00407
    00408         #if DBG1
    00409         if (DPRN0)
    00410         DbgPrint("Wait %x deregister waiting ThreadId<%x:%x>\n\n",
    00411                 (ULONG_PTR)Wait,
    00412                 HandleToUlong(NtCurrentTeb()->ClientId.UniqueThread),
    00413                 HandleToUlong(NtCurrentTeb()->ClientId.UniqueProcess)) ;
    00414         #endif
    00415
    00416         Status = RtlpWaitForEvent( CompletionEvent->Handle, ThreadHandle ) ;
    00417
    00418         #if DBG1
    00419         if (DPRN0)
    00420         DbgPrint("Wait %x deregister completed\n\n", (ULONG_PTR)Wait) ;
    00421         #endif
    00422
    00423         RtlpFreeWaitEvent( CompletionEvent ) ;
    00424
    00425         return NT_SUCCESS( Status ) ? STATUS_SUCCESS : Status ;
    00426
    00427     } else {
    00428
    00429         return StatusAsync ;
    00430     }
    00431 }

VOID RtlpAddTimer | ( | PRTLP_TIMER | Timer | ) |

Definition at line 3954 of file threads.c.

References NULL, PRTLP_TIMER_QUEUE, RtlpDeleteTimer(), RtlpGetQueueRelativeTime(), RtlpGetTimeRemaining(), RtlpInsertInDeltaList(), RtlpReOrderDeltaList(), RtlpResetTimer(), RtlpResync64BitTickCount(), STATE_ACTIVE, STATE_DELETE, STATE_REGISTERED, TimerHandle, and TimerQueues.

Referenced by RtlCreateTimer().

    03959                    :
    03960
    03961     This routine runs as an APC into the Timer thread. It adds a new timer to the
    03962     specified queue.
    03963
    03964 Arguments:
    03965
    03966     Timer - Pointer to the timer to add
    03967
    03968 Return Value:
    03969
    03970
    03971 --*/
    03972 {
    03973     PRTLP_TIMER_QUEUE Queue ;
    03974     ULONG TimeRemaining, QueueRelTimeRemaining ;
    03975     ULONG NewFiringTime ;
    03976
    03977     RtlpResync64BitTickCount() ;
    03978
    03979
    03980     // the timer was set to be deleted in a callback function.
    03981
    03982     if (Timer->State & STATE_DELETE ) {
    03983
    03984         RtlpDeleteTimer( Timer ) ;
    03985         return ;
    03986     }
    03987
    03988
    03989     Queue = Timer->Queue ;
    03990
    03991
    03992     // TimeRemaining is the time left in the current timer + the relative time of
    03993     // the queue it is being inserted into
    03994
    03995     TimeRemaining = RtlpGetTimeRemaining (TimerHandle) ;
    03996     QueueRelTimeRemaining = TimeRemaining + RtlpGetQueueRelativeTime (Queue) ;
    03997
    03998
    03999     if (RtlpInsertInDeltaList (&Queue->TimerList, Timer, QueueRelTimeRemaining,
    04000                                 &NewFiringTime))
    04001     {
    04002
    04003         // If the Queue is not attached to TimerQueues since it had no timers
    04004         // previously then insert the queue into the TimerQueues list, else just
    04005         // reorder its existing position.
    04006
    04007         if (IsListEmpty (&Queue->List)) {
    04008
    04009             Queue->DeltaFiringTime = NewFiringTime ;
    04010
    04011             if (RtlpInsertInDeltaList (&TimerQueues, Queue, TimeRemaining,
    04012                                         &NewFiringTime))
    04013             {
    04014
    04015                 // There is a new element at the head of the queue we need to reset the NT
    04016                 // timer to fire sooner.
    04017
    04018                 RtlpResetTimer (TimerHandle, NewFiringTime, NULL) ;
    04019             }
    04020
    04021         } else {
    04022
    04023             // If we insert at the head of the timer delta list we will need to
    04024             // make sure the queue delta list is readjusted
    04025
    04026             if (RtlpReOrderDeltaList(&TimerQueues, Queue, TimeRemaining, &NewFiringTime, NewFiringTime)){
    04027
    04028                 // There is a new element at the head of the queue we need to reset the NT
    04029                 // timer to fire sooner.
    04030
    04031                 RtlpResetTimer (TimerHandle, NewFiringTime, NULL) ;
    04032
    04033             }
    04034         }
    04035
    04036     }
    04037
    04038     Timer->State |= ( STATE_REGISTERED | STATE_ACTIVE ) ;
    04039 }

VOID RtlpAddTimerQueue | ( | PVOID | Queue | ) |

Definition at line 4794 of file threads.c.

    04799                    :
    04800
    04801     This routine runs as an APC into the Timer thread. It does whatever necessary to
    04802     create a new timer queue
    04803
    04804 Arguments:
    04805
    04806     Queue - Pointer to the queue to add
    04807
    04808 Return Value:
    04809
    04810
    04811 --*/
    04812 {
    04813
    04814     // We do nothing here. The newly created queue is free floating until a timer is
    04815     // queued onto it.
    04816
    04817 }

VOID RtlpAddWait | ( | PRTLP_WAIT | Wait | ) |

Definition at line 3302 of file threads.c.

References _RTLP_WAIT_THREAD_CONTROL_BLOCK::ActiveWaitArray, _RTLP_WAIT_THREAD_CONTROL_BLOCK::ActiveWaitPointers, ASSERT, _RTLP_GENERIC_TIMER::Context, _RTLP_WAIT::Context, _RTLP_GENERIC_TIMER::DeltaFiringTime, FALSE, _RTLP_GENERIC_TIMER::Flags, _RTLP_WAIT::Flags, _RTLP_WAIT_THREAD_CONTROL_BLOCK::FreeTimerBlocks, _RTLP_GENERIC_TIMER::Function, _RTLP_WAIT::Function, INFINITE_TIME, NULL, _RTLP_WAIT_THREAD_CONTROL_BLOCK::NumActiveWaits, _RTLP_WAIT_THREAD_CONTROL_BLOCK::NumWaits, _RTLP_GENERIC_TIMER::Period, PRTLP_TIMER, _RTLP_GENERIC_TIMER::Queue, _RTLP_WAIT::RefCount, _RTLP_GENERIC_TIMER::RefCountPtr, RtlpDeleteWait(), RtlpGetTimeRemaining(), RtlpInsertInDeltaList(), RtlpResetTimer(), _RTLP_WAIT::State, _RTLP_GENERIC_TIMER::State, STATE_ACTIVE, STATE_DELETE, STATE_REGISTERED, _RTLP_WAIT::ThreadCB, _RTLP_WAIT::Timeout, _RTLP_WAIT::Timer, _RTLP_WAIT_THREAD_CONTROL_BLOCK::TimerHandle, _RTLP_WAIT_THREAD_CONTROL_BLOCK::TimerQueue, _RTLP_GENERIC_TIMER::Wait, and _RTLP_WAIT::WaitHandle.

Referenced by RtlRegisterWait().

    03307                    :
    03308
    03309     This routine is used for adding waits to the wait thread. It is executed in
    03310     an APC.
    03311
    03312 Arguments:
    03313
    03314     Wait - The wait to add
    03315
    03316 Return Value:
    03317
    03318 --*/
    03319 {
    03320     PRTLP_WAIT_THREAD_CONTROL_BLOCK ThreadCB = Wait->ThreadCB;
    03321
    03322
    03323     // if the state is deleted, it implies that RtlDeregister was called in a
    03324     // WaitThreadCallback for a Wait other than that which was fired. This is
    03325     // an application bug. I Assert, but also handle it.
    03326
    03327     if ( Wait->State & STATE_DELETE ) {
    03328
    03329         ASSERT(FALSE) ;
    03330
    03331         InterlockedDecrement( &ThreadCB->NumWaits ) ;
    03332
    03333         RtlpDeleteWait (Wait) ;
    03334
    03335         return ;
    03336     }
    03337
    03338
    03339     // activate Wait
    03340
    03341     ThreadCB->ActiveWaitArray [ThreadCB->NumActiveWaits] = Wait->WaitHandle ;
    03342     ThreadCB->ActiveWaitPointers[ThreadCB->NumActiveWaits] = Wait ;
    03343     ThreadCB->NumActiveWaits ++ ;
    03344     Wait->State |= (STATE_REGISTERED | STATE_ACTIVE) ;
    03345     Wait->RefCount = 1 ;
    03346
    03347
    03348     // Fill in the wait timer
    03349
    03350     if (Wait->Timeout != INFINITE_TIME) {
    03351
    03352         ULONG TimeRemaining ;
    03353         ULONG NewFiringTime ;
    03354
    03355         // Initialize timer related fields and insert the timer in the timer queue for
    03356         // this wait thread
    03357
    03358         Wait->Timer = (PRTLP_TIMER) RemoveHeadList(&ThreadCB->FreeTimerBlocks);
    03359         Wait->Timer->Function = Wait->Function ;
    03360         Wait->Timer->Context = Wait->Context ;
    03361         Wait->Timer->Flags = Wait->Flags ;
    03362         Wait->Timer->DeltaFiringTime = Wait->Timeout ;
    03363         Wait->Timer->Period = ( Wait->Flags & WT_EXECUTEONLYONCE )
    03364                                 ? 0
    03365                                 : Wait->Timeout == INFINITE_TIME
    03366                                 ? 0 : Wait->Timeout ;
    03367
    03368         Wait->Timer->State = ( STATE_REGISTERED | STATE_ACTIVE ) ; ;
    03369         Wait->Timer->Wait = Wait ;
    03370         Wait->Timer->RefCountPtr = &Wait->RefCount ;
    03371         Wait->Timer->Queue = &ThreadCB->TimerQueue ;
    03372
    03373
    03374         TimeRemaining = RtlpGetTimeRemaining (ThreadCB->TimerHandle) ;
    03375
    03376         if (RtlpInsertInDeltaList (&ThreadCB->TimerQueue.TimerList, Wait->Timer,
    03377                                     TimeRemaining, &NewFiringTime))
    03378         {
    03379             // If the element was inserted at head of list then reset the timers
    03380
    03381             RtlpResetTimer (ThreadCB->TimerHandle, NewFiringTime, ThreadCB) ;
    03382         }
    03383
    03384     } else {
    03385
    03386         // No timer with this wait
    03387
    03388         Wait->Timer = NULL ;
    03389
    03390     }
    03391
    03392     return ;
    03393 }

VOID RtlpAsyncCallbackCompletion | ( | PVOID | Context | ) |

Definition at line 3082 of file threads.c.

References _RTLP_WAIT::Context, DBG_SET_FUNCTION, DbgPrint, DPRN4, _RTLP_WAIT::Function, PRTLP_ASYNC_CALLBACK, PRTLP_TIMER, _RTLP_WAIT::RefCount, RtlpDeleteTimer(), RtlpDeleteWait(), RtlpFreeTPHeap, _RTLP_WAITWORKER::Timer, _RTLP_WAITWORKER::TimerCondition, TRUE, _RTLP_WAITWORKER::Wait, and _RTLP_WAITWORKER::WaitThreadCallback.

Referenced by RtlpFireTimers(), and RtlpProcessWaitCompletion().

    03087                    :
    03088
    03089     This routine is called in a (IO)worker thread and is used to decrement the
    03090     RefCount at the end and call RtlpDelete(Wait/Timer) if required
    03091
    03092 Arguments:
    03093
    03094     Context - AsyncCallback: containing pointer to Wait/Timer object,
    03095
    03096 Return Value:
    03097
    03098 --*/
    03099 {
    03100     PRTLP_ASYNC_CALLBACK AsyncCallback ;
    03101
    03102     AsyncCallback = (PRTLP_ASYNC_CALLBACK) Context ;
    03103
    03104     // callback queued by WaitThread (event or timer)
    03105
    03106     if ( AsyncCallback->WaitThreadCallback ) {
    03107
    03108         PRTLP_WAIT Wait = AsyncCallback->Wait ;
    03109
    03110         //DPRN5
    03111         if (DPRN4)
    03112         DbgPrint("Calling WaitOrTimer: fn:%x  context:%x  bool:%d Thread<%d:%d>\n",
    03113                 (ULONG_PTR)Wait->Function, (ULONG_PTR)Wait->Context,
    03114                 (ULONG_PTR)AsyncCallback->TimerCondition,
    03115                 HandleToUlong(NtCurrentTeb()->ClientId.UniqueThread),
    03116                 HandleToUlong(NtCurrentTeb()->ClientId.UniqueProcess)
    03117                 ) ;
    03118
    03119         #if (DBG1)
    03120         DBG_SET_FUNCTION( Wait->Function, Wait->Context ) ;
    03121         #endif
    03122
    03123         ((WAITORTIMERCALLBACKFUNC) Wait->Function)
    03124                                 ( Wait->Context, AsyncCallback->TimerCondition ) ;
    03125
    03126         if ( InterlockedDecrement( &Wait->RefCount ) == 0 ) {
    03127
    03128             RtlpDeleteWait( Wait ) ;
    03129         }
    03130
    03131     }
    03132
    03133     // callback queued by TimerThread
    03134
    03135     else {
    03136
    03137         PRTLP_TIMER Timer = AsyncCallback->Timer ;
    03138
    03139         //DPRN5
    03140         if (DPRN4)
    03141         DbgPrint("Calling WaitOrTimer:Timer: fn:%x  context:%x  bool:%d Thread<%d:%d>\n",
    03142                 (ULONG_PTR)Timer->Function, (ULONG_PTR)Timer->Context,
    03143                 TRUE,
    03144                 HandleToUlong(NtCurrentTeb()->ClientId.UniqueThread),
    03145                 HandleToUlong(NtCurrentTeb()->ClientId.UniqueProcess)
    03146                 ) ;
    03147
    03148         #if (DBG1)
    03149         DBG_SET_FUNCTION( Timer->Function, Timer->Context ) ;
    03150         #endif
    03151
    03152
    03153         ((WAITORTIMERCALLBACKFUNC) Timer->Function) ( Timer->Context , TRUE) ;
    03154
    03155
    03156         // decrement RefCount after function is executed so that the context is not deleted
    03157
    03158         if ( InterlockedDecrement( &Timer->RefCount ) == 0 ) {
    03159
    03160             RtlpDeleteTimer( Timer ) ;
    03161         }
    03162
    03163     }
    03164
    03165
    03166     RtlpFreeTPHeap( AsyncCallback );
    03167
    03168 }

VOID RtlpCancelTimer | ( | PRTLP_TIMER | Timer | ) |

Definition at line 4120 of file threads.c.

References FALSE, and RtlpCancelTimerEx().

Referenced by RtlDeleteTimer().

    04125                    :
    04126
    04127     This routine executes in an APC and cancels the specified timer if it exists
    04128
    04129 Arguments:
    04130
    04131     Timer - Specifies pointer to a timer structure that contains Queue and Timer information
    04132
    04133 Return Value:
    04134
    04135
    04136 --*/
    04137 {
    04138     RtlpCancelTimerEx( Timer, FALSE ) ; // queue not being deleted
    04139 }

VOID RtlpCancelTimerEx | ( | PRTLP_TIMER | Timer,
|  | BOOLEAN | DeletingQueue
| ) |

Definition at line 4142 of file threads.c.

References CHECK_SIGNATURE, PRTLP_TIMER_QUEUE, RtlpDeactivateTimer(), RtlpDeleteTimer(), RtlpResync64BitTickCount(), STATE_ACTIVE, and STATE_DELETE.

Referenced by RtlpCancelTimer(), and RtlpDeleteTimerQueue().

    04148                    :
    04149
    04150     This routine cancels the specified timer.
    04151
    04152 Arguments:
    04153
    04154     Timer - Specifies pointer to a timer structure that contains Queue and Timer information
    04155     DeletingQueue - FALSE: routine executing in an APC. Delete timer only.
    04156                     TRUE : routine called by timer queue which is being deleted. So dont
    04157                             reset the queue's position
    04158 Return Value:
    04159
    04160
    04161 --*/
    04162 {
    04163     PRTLP_TIMER_QUEUE Queue ;
    04164
    04165     RtlpResync64BitTickCount() ;
    04166     CHECK_SIGNATURE( Timer ) ;
    04167
    04168     Queue = Timer->Queue ;
    04169
    04170
    04171     if ( Timer->State & STATE_ACTIVE ) {
    04172
    04173         // if queue is being deleted, then the timer should not be reset
    04174
    04175         if ( ! DeletingQueue )
    04176             RtlpDeactivateTimer( Queue, Timer ) ;
    04177
    04178     } else {
    04179
    04180         // remove one shot Inactive timer from Queue->UncancelledTimerList
    04181         // called only when the time queue is being deleted
    04182
    04183         RemoveEntryList( &Timer->List ) ;
    04184
    04185     }
    04186
    04187
    04188     // Set the State to deleted
    04189
    04190     Timer->State |= STATE_DELETE ;
    04191
    04192
    04193     // delete timer if refcount == 0
    04194
    04195     if ( InterlockedDecrement( &Timer->RefCount ) == 0 ) {
    04196
    04197         RtlpDeleteTimer( Timer ) ;
    04198     }
    04199 }

VOID RtlpDeactivateTimer | ( | PRTLP_TIMER_QUEUE | Queue,
|  | PRTLP_TIMER | Timer
| ) |

Definition at line 4202 of file threads.c.

References NULL, RtlpGetQueueRelativeTime(), RtlpGetTimeRemaining(), RtlpRemoveFromDeltaList(), RtlpReOrderDeltaList(), RtlpResetTimer(), TimerHandle, and TimerQueues.

Referenced by RtlpCancelTimerEx().

    04208                    :
    04209
    04210     This routine executes in an APC and cancels the specified timer if it exists
    04211
    04212 Arguments:
    04213
    04214     Timer - Specifies pointer to a timer structure that contains Queue and Timer information
    04215
    04216 Return Value:
    04217
    04218
    04219 --*/
    04220 {
    04221     ULONG TimeRemaining, QueueRelTimeRemaining ;
    04222     ULONG NewFiringTime ;
    04223
    04224
    04225     // Remove the timer from the appropriate queue
    04226
    04227     TimeRemaining = RtlpGetTimeRemaining (TimerHandle) ;
    04228     QueueRelTimeRemaining = TimeRemaining + RtlpGetQueueRelativeTime (Queue) ;
    04229
    04230     if (RtlpRemoveFromDeltaList (&Queue->TimerList, Timer, QueueRelTimeRemaining, &NewFiringTime)) {
    04231
    04232         // If we removed the last timer from the queue then we should remove the queue
    04233         // from TimerQueues, else we should readjust its position based on the delta time change
    04234
    04235         if (IsListEmpty (&Queue->TimerList)) {
    04236
    04237             // Remove the queue from TimerQueues
    04238
    04239             if (RtlpRemoveFromDeltaList (&TimerQueues, Queue, TimeRemaining, &NewFiringTime)) {
    04240
    04241                 // There is a new element at the head of the queue we need to reset the NT
    04242                 // timer to fire later
    04243
    04244                 RtlpResetTimer (TimerHandle, NewFiringTime, NULL) ;
    04245
    04246             }
    04247
    04248             InitializeListHead (&Queue->List) ;
    04249
    04250         } else {
    04251
    04252             // If we remove from the head of the timer delta list we will need to
    04253             // make sure the queue delta list is readjusted
    04254
    04255             if (RtlpReOrderDeltaList (&TimerQueues, Queue, TimeRemaining, &NewFiringTime, NewFiringTime)) {
    04256
    04257                 // There is a new element at the head of the queue we need to reset the NT
    04258                 // timer to fire later
    04259
    04260                 RtlpResetTimer (TimerHandle, NewFiringTime, NULL) ;
    04261
    04262             }
    04263
    04264         }
    04265
    04266     }
    04267 }

NTSTATUS RtlpDeactivateWait | ( | PRTLP_WAIT | Wait | ) |

Definition at line 3483 of file threads.c.

References _RTLP_WAIT_THREAD_CONTROL_BLOCK::ActiveWaitPointers, ASSERT, FALSE, _RTLP_WAIT_THREAD_CONTROL_BLOCK::FreeTimerBlocks, _RTLP_GENERIC_TIMER::List, NULL, _RTLP_WAIT_THREAD_CONTROL_BLOCK::NumActiveWaits, _RTLP_WAIT_THREAD_CONTROL_BLOCK::NumWaits, RtlpGetTimeRemaining(), RtlpRemoveFromDeltaList(), RtlpResetTimer(), RtlpShiftWaitArray, _RTLP_GENERIC_TIMER::State, _RTLP_WAIT::State, STATE_ACTIVE, _RTLP_WAIT::ThreadCB, _RTLP_WAIT::Timer, _RTLP_WAIT_THREAD_CONTROL_BLOCK::TimerHandle, and _RTLP_WAIT_THREAD_CONTROL_BLOCK::TimerQueue.

Referenced by RtlpDeregisterWait(), RtlpFireTimersAndReorder(), and RtlpProcessWaitCompletion().

    03488                    :
    03489
    03490     This routine is used for deactivating the specified wait. It is executed in a APC.
    03491
    03492 Arguments:
    03493
    03494     Wait - The wait to deactivate
    03495
    03496 Return Value:
    03497
    03498 --*/
    03499 {
    03500     PRTLP_WAIT_THREAD_CONTROL_BLOCK ThreadCB = Wait->ThreadCB ;
    03501     ULONG ArrayIndex ; //Index in ActiveWaitArray where the Wait object is placed
    03502     ULONG EndIndex = ThreadCB->NumActiveWaits -1;
    03503
    03504     // get the index in ActiveWaitArray
    03505
    03506     for (ArrayIndex = 0;  ArrayIndex <= EndIndex; ArrayIndex++) {
    03507
    03508         if (ThreadCB->ActiveWaitPointers[ArrayIndex] == Wait)
    03509             break ;
    03510     }
    03511
    03512     if ( ArrayIndex > EndIndex ) {
    03513
    03514         ASSERT (FALSE) ;
    03515         return STATUS_NOT_FOUND;
    03516     }
    03517
    03518
    03519     // Move the remaining ActiveWaitArray left.
    03520
    03521     RtlpShiftWaitArray( ThreadCB, ArrayIndex+1, ArrayIndex,
    03522                     EndIndex - ArrayIndex ) ;
    03523
    03524
    03525     //
    03526     // delete timer if associated with this wait
    03527     //
    03528     // Though timer is being "freed" here, if it is in the timersToBeFired
    03529     // list, some of its fields will be used later
    03530     //
    03531
    03532     if ( Wait->Timer ) {
    03533
    03534         ULONG TimeRemaining ;
    03535         ULONG NewFiringTime ;
    03536
    03537         if (! (Wait->Timer->State & STATE_ACTIVE) ) {
    03538
    03539             RemoveEntryList( &Wait->Timer->List ) ;
    03540
    03541         } else {
    03542
    03543             TimeRemaining = RtlpGetTimeRemaining (ThreadCB->TimerHandle) ;
    03544
    03545
    03546             if (RtlpRemoveFromDeltaList (&ThreadCB->TimerQueue.TimerList, Wait->Timer,
    03547                                             TimeRemaining, &NewFiringTime))
    03548             {
    03549
    03550                 RtlpResetTimer (ThreadCB->TimerHandle, NewFiringTime, ThreadCB) ;
    03551             }
    03552         }
    03553
    03554
    03555         InsertTailList (&ThreadCB->FreeTimerBlocks, &Wait->Timer->List) ;
    03556
    03557         Wait->Timer = NULL ;
    03558     }
    03559
    03560     // Decrement the (active) wait count
    03561
    03562     ThreadCB->NumActiveWaits-- ;
    03563     InterlockedDecrement( &ThreadCB->NumWaits ) ;
    03564
    03565     Wait->State &= ~STATE_ACTIVE ;
    03566
    03567     return STATUS_SUCCESS;
    03568
    03569 }

VOID RtlpDeleteTimer | ( | PRTLP_TIMER | Timer | ) |

Definition at line 4271 of file threads.c.

References CHECK_SIGNATURE, CLEAR_SIGNATURE, DbgPrint, DPRN1, NtSetEvent(), NULL, PRTLP_TIMER_QUEUE, RtlpDeleteTimerQueueComplete(), and RtlpFreeTPHeap.

Referenced by RtlpAddTimer(), RtlpAsyncCallbackCompletion(), and RtlpCancelTimerEx().

    04276                    :
    04277
    04278     This routine executes in worker or timer thread and deletes the timer
    04279     whose RefCount == 0. The function can be called outside timer thread,
    04280     so no structure outside Timer can be touched (no list etc).
    04281
    04282 Arguments:
    04283
    04284     Timer - Specifies pointer to a timer structure that contains Queue and Timer information
    04285
    04286 Return Value:
    04287
    04288
    04289 --*/
    04290 {
    04291     PRTLP_TIMER_QUEUE Queue = Timer->Queue ;
    04292
    04293     CHECK_SIGNATURE( Timer ) ;
    04294     CLEAR_SIGNATURE( Timer ) ;
    04295
    04296     #if DBG1
    04297     if (DPRN1)
    04298     DbgPrint("<%d> Timer: %x: deleted\n\n", Timer->Queue->DbgId,
    04299             (ULONG_PTR)Timer) ;
    04300     #endif
    04301
    04302     // safe to call this. Either the timer is in the TimersToFireList and
    04303     // the function is being called in time context or else it is not in the
    04304     // list
    04305
    04306     RemoveEntryList( &Timer->TimersToFireList ) ;
    04307
    04308     if ( Timer->CompletionEvent )
    04309         NtSetEvent( Timer->CompletionEvent, NULL ) ;
    04310
    04311
    04312     // decrement the total number of timers in the queue
    04313
    04314     if ( InterlockedDecrement( &Queue->RefCount ) == 0 )
    04315
    04316         RtlpDeleteTimerQueueComplete( Queue ) ;
    04317
    04318
    04319     RtlpFreeTPHeap( Timer ) ;
    04320
    04321 }

NTSTATUS RtlpDeleteTimerQueue | ( | PRTLP_TIMER_QUEUE | Queue | ) |

Definition at line 5354 of file threads.c.

References List, NULL, PRTLP_TIMER, RTLP_TIMER, RtlpCancelTimerEx(), RtlpDeleteTimerQueueComplete(), RtlpGetQueueRelativeTime(), RtlpGetTimeRemaining(), RtlpRemoveFromDeltaList(), RtlpResetTimer(), RtlpResync64BitTickCount(), SET_DEL_TIMERQ_SIGNATURE, TimerHandle, TimerQueues, and TRUE.

Referenced by RtlDeleteTimerQueueEx().

    05359                    :
    05360
    05361     This routine deletes the queue specified in the Request and frees all timers
    05362
    05363 Arguments:
    05364
    05365     Queue - queue to delete
    05366
    05367     Event - Event Handle used for signalling completion of request
    05368
    05369 Return Value:
    05370
    05371 --*/
    05372 {
    05373     ULONG TimeRemaining ;
    05374     ULONG NewFiringTime ;
    05375     PLIST_ENTRY Node ;
    05376     PRTLP_TIMER Timer ;
    05377
    05378     RtlpResync64BitTickCount() ;
    05379
    05380     SET_DEL_TIMERQ_SIGNATURE( Queue ) ;
    05381
    05382
    05383     // If there are no timers in the queue then it is not attached to TimerQueues
    05384     // In this case simply free the memory and return. Otherwise we have to first
    05385     // remove the queue from the TimerQueues List, update the firing time if this
    05386     // was the first queue in the list and then walk all the timers and free them
    05387     // before freeing the Timer Queue.
    05388
    05389     if (!IsListEmpty (&Queue->List)) {
    05390
    05391         TimeRemaining = RtlpGetTimeRemaining (TimerHandle)
    05392                         + RtlpGetQueueRelativeTime (Queue) ;
    05393
    05394         if (RtlpRemoveFromDeltaList (&TimerQueues, Queue, TimeRemaining,
    05395                                     &NewFiringTime))
    05396         {
    05397
    05398             // If removed from head of queue list, reset the timer
    05399
    05400             RtlpResetTimer (TimerHandle, NewFiringTime, NULL) ;
    05401         }
    05402
    05403
    05404         // Free all the timers associated with this queue
    05405
    05406         for (Node = Queue->TimerList.Flink ; Node != &Queue->TimerList ; ) {
    05407
    05408             Timer =  CONTAINING_RECORD (Node, RTLP_TIMER, List) ;
    05409
    05410             Node = Node->Flink ;
    05411
    05412             RtlpCancelTimerEx( Timer ,TRUE ) ; // Queue being deleted
    05413         }
    05414     }
    05415
    05416
    05417     // Free all the uncancelled one shot timers in this queue
    05418
    05419     for (Node = Queue->UncancelledTimerList.Flink ; Node != &Queue->UncancelledTimerList ; ) {
    05420
    05421         Timer =  CONTAINING_RECORD (Node, RTLP_TIMER, List) ;
    05422
    05423         Node = Node->Flink ;
    05424
    05425         RtlpCancelTimerEx( Timer ,TRUE ) ; // Queue being deleted
    05426     }
    05427
    05428
    05429     // delete the queue completely if the RefCount is 0
    05430
    05431     if ( InterlockedDecrement( &Queue->RefCount ) == 0 ) {
    05432
    05433         RtlpDeleteTimerQueueComplete( Queue ) ;
    05434
    05435         return STATUS_SUCCESS ;
    05436
    05437     } else {
    05438
    05439         return STATUS_PENDING ;
    05440     }
    05441
    05442 }

VOID RtlpDeleteTimerQueueComplete | ( | PRTLP_TIMER_QUEUE | Queue | ) |

Definition at line 5462 of file threads.c.

References DbgPrint, DPRN1, NtSetEvent(), NULL, NumTimerQueues, and RtlpFreeTPHeap.

Referenced by RtlpDeleteTimer(), and RtlpDeleteTimerQueue().

    05465 {
    05466     #if DBG1
    05467     if (DPRN1)
    05468     DbgPrint("<%d> Queue: %x: deleted\n\n", Queue->DbgId,
    05469             (ULONG_PTR)Queue) ;
    05470     #endif
    05471
    05472     InterlockedDecrement( &NumTimerQueues ) ;
    05473
    05474     // Notify the thread issuing the cancel that the request is completed
    05475
    05476     if ( Queue->CompletionEvent )
    05477         NtSetEvent (Queue->CompletionEvent, NULL) ;
    05478
    05479     RtlpFreeTPHeap( Queue ) ;
    05480 }

VOID RtlpDeleteWait | ( | PRTLP_WAIT | Wait | ) |

Definition at line 3573 of file threads.c.

References CHECK_SIGNATURE, CLEAR_SIGNATURE, _RTLP_WAIT::DbgId, DbgPrint, DPRN1, NtSetEvent(), NULL, and RtlpFreeTPHeap.

Referenced by RtlpAddWait(), RtlpAsyncCallbackCompletion(), RtlpDeregisterWait(), and RtlpProcessWaitCompletion().

    03578                    :
    03579
    03580     This routine is used for deleting the specified wait. It can be executed
    03581     outside the context of the wait thread. So structure except the WaitEntry
    03582     can be changed. It also sets the event.
    03583
    03584 Arguments:
    03585
    03586     Wait - The wait to delete
    03587
    03588 Return Value:
    03589
    03590 --*/
    03591 {
    03592     CHECK_SIGNATURE( Wait ) ;
    03593     CLEAR_SIGNATURE( Wait ) ;
    03594
    03595     #if DBG1
    03596     if (DPRN1)
    03597     DbgPrint("<%d> Wait %x deleted in thread:%d\n\n", Wait->DbgId,
    03598             (ULONG_PTR)Wait,
    03599             HandleToUlong(NtCurrentTeb()->ClientId.UniqueThread)) ;
    03600     #endif
    03601
    03602
    03603     if ( Wait->CompletionEvent ) {
    03604
    03605         NtSetEvent( Wait->CompletionEvent, NULL ) ;
    03606     }
    03607
    03608     RtlpFreeTPHeap( Wait) ;
    03609
    03610     return ;
    03611 }

NTSTATUS RtlpDeregisterWait | ( | PRTLP_WAIT | Wait,
|  | HANDLE | PartialCompletionEvent,
|  | PULONG | RetStatusPtr
| ) |

Definition at line 3397 of file threads.c.

References CHECK_SIGNATURE, NT_SUCCESS, NtSetEvent(), NULL, _RTLP_WAIT::RefCount, RtlpDeactivateWait(), RtlpDeleteWait(), _RTLP_WAIT::State, STATE_ACTIVE, STATE_DELETE, STATE_REGISTERED, and Status.

Referenced by RtlDeregisterWaitEx().

    03404                    :
    03405
    03406     This routine is used for deregistering the specified wait.
    03407
    03408 Arguments:
    03409
    03410     Wait - The wait to deregister
    03411
    03412 Return Value:
    03413
    03414 --*/
    03415 {
    03416     ULONG Status = STATUS_SUCCESS ;
    03417     ULONG DontUse ;
    03418     PULONG RetStatus = RetStatusPtr ? RetStatusPtr : &DontUse;
    03419
    03420     CHECK_SIGNATURE(Wait) ;
    03421
    03422
    03423     // RtlpDeregisterWait can be called on a wait that has not yet been
    03424     // registered. This indicates that someone calls a RtlDeregisterWait
    03425     // inside a WaitThreadCallback for a Wait other than that was fired.
    03426     // Application bug!! I assert but handle it
    03427
    03428     if ( ! (Wait->State & STATE_REGISTERED) ) {
    03429
    03430         // set state to deleted, so that it does not get registered
    03431
    03432         Wait->State |= STATE_DELETE ;
    03433
    03434         InterlockedDecrement( &Wait->RefCount ) ;
    03435
    03436         if ( PartialCompletionEvent ) {
    03437
    03438             NtSetEvent( PartialCompletionEvent, NULL ) ;
    03439         }
    03440
    03441         *RetStatus = STATUS_SUCCESS ;
    03442         return STATUS_SUCCESS ;
    03443     }
    03444
    03445
    03446     // deactivate wait.
    03447
    03448     if ( Wait->State & STATE_ACTIVE ) {
    03449
    03450         if ( ! NT_SUCCESS( RtlpDeactivateWait ( Wait ) ) ) {
    03451
    03452             *RetStatus = STATUS_NOT_FOUND ;
    03453             return STATUS_NOT_FOUND ;
    03454         }
    03455     }
    03456
    03457     // delete wait if RefCount == 0
    03458
    03459     Wait->State |= STATE_DELETE ;
    03460
    03461     if ( InterlockedDecrement (&Wait->RefCount) == 0 ) {
    03462
    03463         RtlpDeleteWait ( Wait ) ;
    03464
    03465         Status = *RetStatus = STATUS_SUCCESS ;
    03466
    03467     } else {
    03468
    03469         Status = *RetStatus = STATUS_PENDING ;
    03470     }
    03471
    03472     if ( PartialCompletionEvent ) {
    03473
    03474         NtSetEvent( PartialCompletionEvent, NULL ) ;
    03475     }
    03476
    03477
    03478     return Status ;
    03479 }

VOID RtlpDoNothing | ( | PVOID | NotUsed1,
|  | PVOID | NotUsed2,
|  | PVOID | NotUsed3
| ) |

Definition at line 3617 of file threads.c.

Referenced by RtlpWaitForEvent().

    03624                    :
    03625
    03626     This routine is used to see if the thread is alive
    03627
    03628 Arguments:
    03629
    03630     NotUsed1, NotUsed2 and NotUsed 3 - not used
    03631
    03632 Return Value:
    03633
    03634     None
    03635
    03636 --*/
    03637 {
    03638
    03639 }

VOID RtlpExecuteIOWorkItem | ( | PVOID | Function,
|  | PVOID | Context,
|  | PVOID | NotUsed
| ) |

Definition at line 2632 of file threads.c.

References ASSERT, DBG_SET_FUNCTION, EXCEPTION_EXECUTE_HANDLER, FALSE, and NumIOWorkRequests.

Referenced by RtlpQueueIOWorkerRequest().

    02639                    :
    02640
    02641     Executes an IO Work function. RUNs in a APC in the IO Worker thread.
    02642
    02643 Arguments:
    02644
    02645     Function - Worker function to call
    02646
    02647     Context - Argument for the worker function.
    02648
    02649     NotUsed - Argument is not used in this function.
    02650
    02651 Return Value:
    02652
    02653
    02654 --*/
    02655 {
    02656     #if (DBG1)
    02657     DBG_SET_FUNCTION( Function, Context ) ;
    02658     #endif
    02659
    02660     // Invoke the function
    02661
    02662     try {
    02663         ((WORKERCALLBACKFUNC) Function)((PVOID)Context) ;
    02664     } except (EXCEPTION_EXECUTE_HANDLER) {
    02665         ASSERT(FALSE);
    02666     }
    02667
    02668     // Decrement pending IO requests count
    02669
    02670     InterlockedDecrement (&NumIOWorkRequests) ;
    02671
    02672 }

VOID RtlpExecuteLongIOWorkItem | ( | PVOID | Function,
|  | PVOID | Context,
|  | PVOID | ThreadCB
| ) |

Definition at line 2583 of file threads.c.

References ASSERT, DBG_SET_FUNCTION, EXCEPTION_EXECUTE_HANDLER, FALSE, NumIOWorkRequests, and NumLongIOWorkRequests.

    02590                    :
    02591
    02592     Executes an IO Work function. RUNs in a APC in the IO Worker thread.
    02593
    02594 Arguments:
    02595
    02596     Function - Worker function to call
    02597
    02598     Context - Argument for the worker function.
    02599
    02600     NotUsed - Argument is not used in this function.
    02601
    02602 Return Value:
    02603
    02604 --*/
    02605 {
    02606     #if (DBG1)
    02607     DBG_SET_FUNCTION( Function, Context ) ;
    02608     #endif
    02609
    02610     // Invoke the function
    02611
    02612     try {
    02613         ((WORKERCALLBACKFUNC) Function)((PVOID)Context) ;
    02614     } except (EXCEPTION_EXECUTE_HANDLER) {
    02615         ASSERT(FALSE);
    02616     }
    02617
    02618
    02619     ((PRTLP_IOWORKER_TCB)ThreadCB)->LongFunctionFlag = FALSE ;
    02620
    02621     // Decrement pending IO requests count
    02622
    02623     InterlockedDecrement (&NumIOWorkRequests) ;
    02624
    02625     // decrement pending long funcitons
    02626
    02627     InterlockedDecrement (&NumLongIOWorkRequests ) ;
    02628 }

VOID RtlpExecuteWorkerRequest | ( | NTSTATUS | Status,
|  | PVOID | Context,
|  | PVOID | WorkContext
| ) |

Definition at line 1589 of file threads.c.

References DBG_SET_FUNCTION, EXCEPTION_EXECUTE_HANDLER, _RTLP_WORK::Flags, _RTLP_WORK::Function, NumLongWorkRequests, NumWorkRequests, and RtlpFreeTPHeap.

Referenced by RtlpQueueWorkerRequest().

    01596                    :
    01597
    01598     This routine executes a work item.
    01599
    01600 Arguments:
    01601
    01602     Context - contains context to be passed to the callback function.
    01603
    01604     WorkContext - contains callback function ptr and flags
    01605
    01606 Return Value:
    01607
    01608 Notes:
    01609     This function executes in a worker thread or a timer thread if
    01610     WT_EXECUTEINTIMERTHREAD flag is set.
    01611
    01612 --*/
    01613
    01614 {
    01615     PRTLP_WORK WorkEntry = (PRTLP_WORK) WorkContext;
    01616
    01617     #if (DBG1)
    01618     DBG_SET_FUNCTION( WorkEntry->Function, Context ) ;
    01619     #endif
    01620
    01621     try {
    01622         ((WORKERCALLBACKFUNC) WorkEntry->Function) ( Context ) ;
    01623
    01624     } except (EXCEPTION_EXECUTE_HANDLER) {
    01625 //        ASSERT(FALSE);
    01626     }
    01627
    01628     InterlockedDecrement( &NumWorkRequests ) ;
    01629     if (WorkEntry->Flags & WT_EXECUTELONGFUNCTION) {
    01630         InterlockedDecrement( &NumLongWorkRequests ) ;
    01631     }
    01632
    01633     RtlpFreeTPHeap( WorkEntry ) ;
    01634 }

NTSTATUS RtlpExitThread | ( | NTSTATUS | Status | ) |

Definition at line 2738 of file threads.c.

References NtTerminateThread(), and Status.

    02741 {
    02742     return NtTerminateThread( NtCurrentThread(), Status );
    02743 }

NTSTATUS RtlpFindWaitThread | ( | PRTLP_WAIT_THREAD_CONTROL_BLOCK * | ThreadCB | ) |

Definition at line 3851 of file threads.c.

References ACQUIRE_GLOBAL_WAIT_LOCK, DbgPrint, NtClose(), NTSTATUS(), RELEASE_GLOBAL_WAIT_LOCK, RtlpStartThreadFunc, RtlpWaitThread(), Status, ThreadHandle, TRUE, and WaitThreads.

Referenced by RtlRegisterWait().

    03856                    :
    03857
    03858     Walks thru the list of wait threads and finds one which can accomodate another wait.
    03859     If one is not found then a new thread is created.
    03860
    03861     This routine assumes that the caller has the GlobalWaitLock.
    03862
    03863 Arguments:
    03864
    03865     ThreadCB: returns the ThreadCB of the wait thread that will service the wait request.
    03866
    03867 Return Value:
    03868
    03869     STATUS_SUCCESS if a wait thread was allocated,
    03870
    03871 --*/
    03872 {
    03873     NTSTATUS Status = STATUS_SUCCESS;
    03874     PLIST_ENTRY Node ;
    03875     HANDLE ThreadHandle ;
    03876     PRTLP_WAIT_THREAD_CONTROL_BLOCK ThreadCBTmp;
    03877
    03878
    03879     ACQUIRE_GLOBAL_WAIT_LOCK() ;
    03880
    03881     do {
    03882
    03883         // Walk thru the list of Wait Threads and find a Wait thread that can accomodate a
    03884         // new wait request.
    03885
    03886         // *Consider* finding a wait thread with least # of waits to facilitate better
    03887         // load balancing of waits.
    03888
    03889
    03890         for (Node = WaitThreads.Flink ; Node != &WaitThreads ; Node = Node->Flink) {
    03891
    03892             ThreadCBTmp = CONTAINING_RECORD (Node, RTLP_WAIT_THREAD_CONTROL_BLOCK,
    03893                                             WaitThreadsList) ;
    03894
    03895
    03896             // Wait Threads can accomodate upto 64 waits (NtWaitForMultipleObject limit)
    03897
    03898             if ((ThreadCBTmp)->NumWaits < 64) {
    03899
    03900                 // Found a thread with some wait slots available.
    03901
    03902                 InterlockedIncrement ( &(ThreadCBTmp)->NumWaits) ;
    03903
    03904                 *ThreadCB = ThreadCBTmp;
    03905
    03906                 RELEASE_GLOBAL_WAIT_LOCK() ;
    03907
    03908                 return STATUS_SUCCESS ;
    03909             }
    03910
    03911         }
    03912
    03913
    03914         // If we reach here, we dont have any more wait threads. so create a new wait thread.
    03915
    03916         Status = RtlpStartThreadFunc (RtlpWaitThread, &ThreadHandle) ;
    03917
    03918
    03919         // If thread creation fails then return the failure to caller
    03920
    03921         if (Status != STATUS_SUCCESS ) {
    03922
    03923             #if DBG
    03924             DbgPrint("ERROR!! ThreadPool: could not create wait thread\n");
    03925             #endif
    03926
    03927             RELEASE_GLOBAL_WAIT_LOCK() ;
    03928
    03929             return Status ;
    03930
    03931         } else {
    03932
    03933             // Close Thread handle, we dont need it.
    03934
    03935             NtClose (ThreadHandle) ;
    03936         }
    03937
    03938         // Loop back now that we have created another thread
    03939
    03940     } while (TRUE) ;    // Loop back to top and put new wait request in the newly created thread
    03941
    03942     RELEASE_GLOBAL_WAIT_LOCK() ;
    03943
    03944     return Status ;
    03945 }

VOID RtlpFireTimers | ( | PLIST_ENTRY | TimersToFireList | ) |

Definition at line 3747 of file threads.c.

References DBG_SET_FUNCTION, DbgPrint, DPRN4, FALSE, NT_SUCCESS, NTSTATUS(), NULL, PRTLP_TIMER, RTLP_TIMER, RtlpAsyncCallbackCompletion(), RtlpForceAllocateTPHeap(), RtlpFreeTPHeap, RtlQueueWorkItem(), STATE_DONTFIRE, Status, _RTLP_WAITWORKER::Timer, _RTLP_WAITWORKER::TimerCondition, TRUE, _RTLP_WAITWORKER::Wait, and _RTLP_WAITWORKER::WaitThreadCallback.

Referenced by RtlpProcessTimeouts(), and RtlpServiceTimer().

    03752                    :
    03753
    03754     Finally all the timers are fired here.
    03755
    03756 Arguments:
    03757
    03758     TimersToFireList: List of timers to fire
    03759
    03760 --*/
    03761
    03762 {
    03763     PLIST_ENTRY Node ;
    03764     PRTLP_TIMER Timer ;
    03765     NTSTATUS Status;
    03766
    03767
    03768     for (Node = TimersToFireList->Flink;  Node != TimersToFireList; Node = TimersToFireList->Flink)
    03769     {
    03770         Timer = CONTAINING_RECORD (Node, RTLP_TIMER, TimersToFireList) ;
    03771
    03772         RemoveEntryList( Node ) ;
    03773         InitializeListHead( Node ) ;
    03774
    03775
    03776         if ( (Timer->State & STATE_DONTFIRE)
    03777             || (Timer->Queue->State & STATE_DONTFIRE) )
    03778         {
    03779             ;
    03780
    03781         } else if ( Timer->Flags & (WT_EXECUTEINTIMERTHREAD | WT_EXECUTEINWAITTHREAD ) ) {
    03782
    03783             //DPRN5
    03784             if (DPRN4)
    03785             DbgPrint("Calling WaitOrTimer(Timer): fn:%x  context:%x  bool:%d Thread<%d:%d>\n",
    03786                 (ULONG_PTR)Timer->Function, (ULONG_PTR)Timer->Context,
    03787                 TRUE,
    03788                 HandleToUlong(NtCurrentTeb()->ClientId.UniqueThread),
    03789                 HandleToUlong(NtCurrentTeb()->ClientId.UniqueProcess)
    03790                 ) ;
    03791
    03792             #if (DBG1)
    03793             DBG_SET_FUNCTION( Timer->Function, Timer->Context ) ;
    03794             #endif
    03795
    03796
    03797             ((WAITORTIMERCALLBACKFUNC) Timer->Function) (Timer->Context, TRUE) ;
    03798
    03799         } else {
    03800
    03801             // create context for Callback and queue it appropriately
    03802
    03803             PRTLP_ASYNC_CALLBACK  AsyncCallback ;
    03804
    03805             AsyncCallback = RtlpForceAllocateTPHeap(
    03806                                     sizeof( RTLP_ASYNC_CALLBACK ),
    03807                                     0 );
    03808             AsyncCallback->TimerCondition = TRUE ;
    03809
    03810             // timer associated with WaitEvents should be treated differently
    03811
    03812             if ( Timer->Wait != NULL ) {
    03813
    03814                 AsyncCallback->Wait = Timer->Wait ;
    03815                 AsyncCallback->WaitThreadCallback = TRUE ;
    03816
    03817                 InterlockedIncrement( Timer->RefCountPtr ) ;
    03818
    03819             } else {
    03820
    03821                 AsyncCallback->Timer = Timer ;
    03822                 AsyncCallback->WaitThreadCallback = FALSE ;
    03823
    03824                 InterlockedIncrement( &Timer->RefCount ) ;
    03825             }
    03826
    03827
    03828             // queue work item
    03829
    03830             Status = RtlQueueWorkItem( RtlpAsyncCallbackCompletion, AsyncCallback,
    03831                                 Timer->Flags );
    03832
    03833             if (!NT_SUCCESS(Status)) {
    03834
    03835                 RtlpFreeTPHeap( AsyncCallback );
    03836                 if ( Timer->Wait != NULL ) {
    03837                     InterlockedDecrement( Timer->RefCountPtr ) ;
    03838                 } else {
    03839                     InterlockedDecrement( &Timer->RefCount ) ;
    03840                 }
    03841             }
    03842
    03843         }
    03844
    03845
    03846     }
    03847 }

VOID RtlpFireTimersAndReorder | ( | PRTLP_TIMER_QUEUE | Queue,
|  | ULONG * | NewFiringTime,
|  | PLIST_ENTRY | TimersToFireList
| ) |

Definition at line 5010 of file threads.c.

References INFINITE_TIME, List, PRTLP_TIMER, RTLP_TIMER, RtlpDeactivateWait(), RtlpInsertInDeltaList(), STATE_ACTIVE, STATE_DONTFIRE, and STATE_ONE_SHOT_FIRED.

Referenced by RtlpProcessTimeouts(), and RtlpServiceTimer().

    05017                    :
    05018
    05019     Fires all timers in TimerList that have DeltaFiringTime == 0. After firing the timers
    05020     it reorders the timers based on their periodic times OR frees the fired one shot timers.
    05021
    05022 Arguments:
    05023
    05024     TimerList - Timer list to work thru.
    05025
    05026     NewFiringTime - Location where the new firing time for the first timer in the delta list
    05027                     is returned.
    05028
    05029
    05030 Return Value:
    05031
    05032
    05033 --*/
    05034 {
    05035     PLIST_ENTRY TNode ;
    05036     PRTLP_TIMER Timer ;
    05037     LIST_ENTRY ReinsertTimerList ;
    05038     PLIST_ENTRY TimerList = &Queue->TimerList ;
    05039
    05040     InitializeListHead (&ReinsertTimerList) ;
    05041     *NewFiringTime = 0 ;
    05042
    05043
    05044     for (TNode = TimerList->Flink ; (TNode != TimerList) && (*NewFiringTime == 0);
    05045             TNode = TimerList->Flink)
    05046     {
    05047
    05048         Timer = CONTAINING_RECORD (TNode, RTLP_TIMER, List) ;
    05049
    05050         // Fire all timers with delta time of 0
    05051
    05052         if (Timer->DeltaFiringTime == 0) {
    05053
    05054             // detach this timer from the list
    05055
    05056             RemoveEntryList (TNode) ;
    05057
    05058             // get next firing time
    05059
    05060             if (!IsListEmpty(TimerList)) {
    05061
    05062                 PRTLP_TIMER TmpTimer ;
    05063
    05064                 TmpTimer = CONTAINING_RECORD (TimerList->Flink, RTLP_TIMER, List) ;
    05065
    05066                 *NewFiringTime  = TmpTimer->DeltaFiringTime ;
    05067
    05068                 TmpTimer->DeltaFiringTime = 0 ;
    05069
    05070             } else {
    05071
    05072                 *NewFiringTime = INFINITE_TIME ;
    05073             }
    05074
    05075
    05076             // if timer is not periodic then remove active state. Timer will be deleted
    05077             // when cancel timer is called.
    05078
    05079             if (Timer->Period == 0) {
    05080
    05081                 InsertHeadList( &Queue->UncancelledTimerList, &Timer->List ) ;
    05082
    05083                 // if one shot wait was timed out then, deactivate the wait
    05084
    05085                 if ( Timer->Wait ) {
    05086
    05087                     //
    05088                     // though timer is being "freed" in this call, it can still be
    05089                     // used after this call
    05090                     //
    05091
    05092                     RtlpDeactivateWait( Timer->Wait ) ;
    05093                 }
    05094
    05095                 else {
    05096                     // should be set at the end
    05097
    05098                     Timer->State &= ~STATE_ACTIVE ;
    05099                 }
    05100
    05101                 Timer->State |= STATE_ONE_SHOT_FIRED ;
    05102
    05103             } else {
    05104
    05105                 // Set the DeltaFiringTime to be the next period
    05106
    05107                 Timer->DeltaFiringTime = Timer->Period ;
    05108
    05109                 // reinsert the timer in the list.
    05110
    05111                 RtlpInsertInDeltaList (TimerList, Timer, *NewFiringTime, NewFiringTime) ;
    05112             }
    05113
    05114
    05115             // Call the function associated with this timer. call it in the end
    05116             // so that RtlTimer calls can be made in the timer function
    05117
    05118             if ( (Timer->State & STATE_DONTFIRE)
    05119                 || (Timer->Queue->State & STATE_DONTFIRE) )
    05120             {
    05121                 ;
    05122
    05123             } else {
    05124
    05125                 InsertTailList( TimersToFireList, &Timer->TimersToFireList ) ;
    05126
    05127             }
    05128
    05129         } else {
    05130
    05131             // No more Timers with DeltaFiringTime == 0
    05132
    05133             break ;
    05134
    05135         }
    05136     }
    05137
    05138
    05139     if ( *NewFiringTime == 0 ) {
    05140         *NewFiringTime = INFINITE_TIME ;
    05141     }
    05142 }

PVOID RtlpForceAllocateTPHeap | ( | ULONG | dwSize,
|  | ULONG | dwFlags
| ) |

Definition at line 5847 of file threads.c.

References dwFlags, FALSE, NtDelayExecution(), ONE_SECOND_TIMEOUT, RtlpAllocateTPHeap, and TRUE.

Referenced by RtlpFireTimers(), RtlpGetWaitEvent(), RtlpProcessWaitCompletion(), and RtlpQueueWorkerRequest().

    05852                    :
    05853
    05854     This routine goes into an infinite loop trying to allocate the memory.
    05855
    05856 Arguments:
    05857
    05858     dwSize - size of memory to be allocated
    05859
    05860     dwFlags - Flags for memory allocation
    05861
    05862 Return Value:
    05863
    05864     ptr to memory
    05865
    05866 --*/
    05867 {
    05868     PVOID ptr;
    05869     ptr = RtlpAllocateTPHeap(dwSize, dwFlags);
    05870     if (ptr)
    05871         return ptr;
    05872
    05873     {
    05874         LARGE_INTEGER TimeOut ;
    05875         do {
    05876
    05877             ONE_SECOND_TIMEOUT(TimeOut) ;
    05878
    05879             NtDelayExecution (FALSE, &TimeOut) ;
    05880
    05881             ptr = RtlpAllocateTPHeap(dwSize, dwFlags);
    05882             if (ptr)
    05883                 break;
    05884
    05885         } while (TRUE) ;
    05886     }
    05887     return ptr;
    05888 }

VOID RtlpFreeWaitEvent | ( | PRTLP_EVENT | Event | ) |

Definition at line 5648 of file threads.c.

References Event(), EventCache, EventCacheCriticalSection, MAX_UNUSED_EVENTS, NtClose(), NULL, NumUnusedEvents, and RtlpFreeTPHeap.

Referenced by RtlDeleteTimer(), RtlDeleteTimerQueueEx(), and RtlDeregisterWaitEx().

    05653                    :
    05654
    05655     Frees the event to the event cache
    05656
    05657 Arguments:
    05658
    05659     Event - the event struct to put back into the cache
    05660
    05661 Return Value:
    05662
    05663     Nothing
    05664
    05665 --*/
    05666 {
    05667
    05668     if ( Event == NULL )
    05669         return ;
    05670
    05671     InitializeListHead (&Event->List) ;
    05672
    05673     RtlEnterCriticalSection (&EventCacheCriticalSection) ;
    05674
    05675     if ( NumUnusedEvents > MAX_UNUSED_EVENTS ) {
    05676
    05677         NtClose( Event->Handle ) ;
    05678
    05679         RtlpFreeTPHeap( Event ) ;
    05680
    05681     } else {
    05682
    05683         InsertHeadList (&EventCache, &Event->List) ;
    05684         NumUnusedEvents++ ;
    05685     }
    05686
    05687
    05688     RtlLeaveCriticalSection (&EventCacheCriticalSection) ;
    05689 }

__inline LONGLONG RtlpGet64BitTickCount | ( | LARGE_INTEGER * | Last64BitTickCount | ) |

Definition at line 3644 of file threads.c.

References Last64BitTickCount, and NtGetTickCount().

Referenced by RtlpProcessTimeouts(), RtlpResetTimer(), RtlpResync64BitTickCount(), and RtlpServiceTimer().

    03649                    :
    03650
    03651     This routine is used for getting the latest 64bit tick count.
    03652
    03653 Arguments:
    03654
    03655 Return Value: 64bit tick count
    03656
    03657 --*/
    03658 {
    03659     LARGE_INTEGER liCurTime ;
    03660
    03661     liCurTime.QuadPart = NtGetTickCount() + Last64BitTickCount->HighPart ;
    03662
    03663     // see if timer has wrapped.
    03664
    03665     if (liCurTime.LowPart < Last64BitTickCount->LowPart) {
    03666         liCurTime.HighPart++ ;
    03667     }
    03668
    03669     return (Last64BitTickCount->QuadPart = liCurTime.QuadPart) ;
    03670 }

ULONG RtlpGetQueueRelativeTime | ( | PRTLP_TIMER_QUEUE | Queue | ) |

Definition at line 4326 of file threads.c.

References List, PRTLP_TIMER_QUEUE, RTLP_TIMER_QUEUE, and TimerQueues.

Referenced by RtlpAddTimer(), RtlpDeactivateTimer(), RtlpDeleteTimerQueue(), and RtlpUpdateTimer().

    04331                    :
    04332
    04333     Walks the list of queues and returns the relative firing time by adding all the
    04334     DeltaFiringTimes for all queues before it.
    04335
    04336 Arguments:
    04337
    04338     Queue - Queue for which to find the relative firing time
    04339
    04340 Return Value:
    04341
    04342     Time in milliseconds
    04343
    04344 --*/
    04345 {
    04346     PLIST_ENTRY Node ;
    04347     ULONG RelativeTime ;
    04348     PRTLP_TIMER_QUEUE CurrentQueue ;
    04349
    04350     RelativeTime = 0 ;
    04351
    04352     // It the Queue is not attached to TimerQueues List because it has no timer
    04353     // associated with it simply returns 0 as the relative time. Else run thru
    04354     // all queues before it in the list and compute the relative firing time
    04355
    04356     if (!IsListEmpty (&Queue->List)) {
    04357
    04358         for (Node = TimerQueues.Flink; Node != &Queue->List; Node=Node->Flink) {
    04359
    04360             CurrentQueue = CONTAINING_RECORD (Node, RTLP_TIMER_QUEUE, List) ;
    04361
    04362             RelativeTime += CurrentQueue->DeltaFiringTime ;
    04363
    04364         }
    04365
    04366         // Add the queue's delta firing time as well
    04367
    04368         RelativeTime += Queue->DeltaFiringTime ;
    04369
    04370     }
    04371
    04372     return RelativeTime ;
    04373
    04374 }

ULONG RtlpGetTimeRemaining | ( | HANDLE | TimerHandle | ) |

Definition at line 4378 of file threads.c.

References ASSERT, NtQueryTimer(), NTSTATUS(), Status, and TimerHandle.

Referenced by RtlDebugPrintTimes(), RtlpAddTimer(), RtlpAddWait(), RtlpDeactivateTimer(), RtlpDeactivateWait(), RtlpDeleteTimerQueue(), RtlpProcessTimeouts(), RtlpProcessWaitCompletion(), RtlpServiceTimer(), and RtlpUpdateTimer().

    04383                    :
    04384
    04385     Gets the time remaining on the specified NT timer
    04386
    04387 Arguments:
    04388
    04389     TimerHandle - Handle to the NT timer
    04390
    04391 Return Value:
    04392
    04393     Time remaining on the timer
    04394
    04395 --*/
    04396 {
    04397     ULONG InfoLen ;
    04398     TIMER_BASIC_INFORMATION Info ;
    04399
    04400     NTSTATUS Status ;
    04401
    04402     Status = NtQueryTimer (TimerHandle, TimerBasicInformation, &Info, sizeof(Info), &InfoLen) ;
    04403
    04404     ASSERT (Status == STATUS_SUCCESS) ;
    04405
    04406     // Return 0 if
    04407     //
    04408     // - the timer has already fired then return
    04409     //   OR
    04410     // - the timer is has more than 0x7f0000000 in its high part
    04411     //   (which indicates that the timer was (probably) programmed for -1)
    04412
    04413
    04414     if (Info.TimerState || ((ULONG)Info.RemainingTime.HighPart > 0x7f000000) ) {
    04415
    04416         return 0 ;
    04417
    04418     } else {
    04419
    04420         return (ULONG) (Info.RemainingTime.QuadPart / 10000) ;
    04421
    04422     }
    04423
    04424 }

PRTLP_EVENT RtlpGetWaitEvent | ( | VOID |  | ) |

Definition at line 5575 of file threads.c.

References CompletedEventCacheInitialization, Event(), EventCache, EventCacheCriticalSection, FALSE, NT_SUCCESS, NtCreateEvent(), NTSTATUS(), NULL, RTLP_EVENT, RtlpForceAllocateTPHeap(), RtlpFreeTPHeap, RtlpInitializeEventCache(), and Status.

Referenced by RtlDeleteTimer(), RtlDeleteTimerQueueEx(), and RtlDeregisterWaitEx().

    05580                    :
    05581
    05582     Returns an event from the event cache.
    05583
    05584 Arguments:
    05585
    05586     None
    05587
    05588 Return Value:
    05589
    05590     Pointer to event structure
    05591
    05592 --*/
    05593 {
    05594     NTSTATUS Status;
    05595     PRTLP_EVENT Event ;
    05596
    05597     if (!CompletedEventCacheInitialization) {
    05598
    05599         RtlpInitializeEventCache () ;
    05600
    05601     }
    05602
    05603     RtlEnterCriticalSection (&EventCacheCriticalSection) ;
    05604
    05605     if (!IsListEmpty (&EventCache)) {
    05606
    05607         Event = (PRTLP_EVENT) RemoveHeadList (&EventCache) ;
    05608
    05609     } else {
    05610
    05611         Event = RtlpForceAllocateTPHeap( sizeof( RTLP_EVENT ), 0 );
    05612
    05613         if (!Event) {
    05614
    05615             RtlLeaveCriticalSection (&EventCacheCriticalSection) ;
    05616
    05617             return NULL ;
    05618
    05619         }
    05620
    05621         Status = NtCreateEvent(
    05622                     &Event->Handle,
    05623                     EVENT_ALL_ACCESS,
    05624                     NULL,
    05625                     SynchronizationEvent,
    05626                     FALSE
    05627                     );
    05628
    05629         if (!NT_SUCCESS(Status) ) {
    05630
    05631             RtlpFreeTPHeap( Event ) ;
    05632
    05633             RtlLeaveCriticalSection (&EventCacheCriticalSection) ;
    05634
    05635             return NULL ;
    05636
    05637         }
    05638
    05639     }
    05640
    05641     RtlLeaveCriticalSection (&EventCacheCriticalSection) ;
    05642
    05643     return Event ;
    05644 }

VOID RtlpInitializeEventCache | ( | VOID |  | ) |

Definition at line 5694 of file threads.c.

References ASSERT, CompletedEventCacheInitialization, EventCache, EventCacheCriticalSection, FALSE, L, NtDelayExecution(), NTSTATUS(), NumUnusedEvents, ONE_MILLISECOND_TIMEOUT, RtlInitializeCriticalSection(), StartedEventCacheInitialization, and Status.

Referenced by RtlpGetWaitEvent().

    05699                    :
    05700
    05701     Initializes the event cache
    05702
    05703 Arguments:
    05704
    05705     None
    05706
    05707 Return Value:
    05708
    05709     Nothing
    05710
    05711 --*/
    05712 {
    05713     NTSTATUS Status;
    05714     LARGE_INTEGER TimeOut ;
    05715
    05716     if (!InterlockedExchange(&StartedEventCacheInitialization, 1L)) {
    05717
    05718         InitializeListHead (&EventCache) ;
    05719
    05720         Status = RtlInitializeCriticalSection(&EventCacheCriticalSection) ;
    05721
    05722         ASSERT (Status == STATUS_SUCCESS) ;
    05723
    05724         NumUnusedEvents = 0 ;
    05725
    05726         InterlockedExchange (&CompletedEventCacheInitialization, 1L) ;
    05727
    05728     } else {
    05729
    05730         // sleep for 1 milliseconds and see if the initialization is complete
    05731
    05732         ONE_MILLISECOND_TIMEOUT(TimeOut) ;
    05733
    05734         while (!(volatile ULONG) CompletedEventCacheInitialization) {
    05735
    05736             NtDelayExecution (FALSE, &TimeOut) ;
    05737
    05738         }
    05739
    05740     }
    05741 }

NTSTATUS RtlpInitializeTimerThreadPool | ( |  | ) |

Definition at line 5256 of file threads.c.

References ASSERT, CompletedTimerInitialization, FALSE, Firing64BitTickCount, L, NT_SUCCESS, NtCreateTimer(), NtDelayExecution(), NtGetTickCount(), NTSTATUS(), NULL, ONE_MILLISECOND_TIMEOUT, Resync64BitTickCount, RtlInitializeCriticalSection(), RtlpStartThreadFunc, RtlpTimerThread(), StartedTimerInitialization, Status, TimerCriticalSection, TimerHandle, TimerQueues, and TimerThreadHandle.

Referenced by RtlCreateTimerQueue(), and RtlpInitializeWorkerThreadPool().

    05260                    :
    05261
    05262     This routine is used to initialize structures used for Timer Thread
    05263
    05264 Arguments:
    05265
    05266
    05267 Return Value:
    05268
    05269 --*/
    05270 {
    05271     NTSTATUS Status = STATUS_SUCCESS;
    05272     LARGE_INTEGER TimeOut ;
    05273
    05274     // In order to avoid an explicit RtlInitialize() function to initialize the wait thread pool
    05275     // we use StartedTimerInitialization and CompletedTimerInitialization to provide us the
    05276     // necessary synchronization to avoid multiple threads from initializing the thread pool.
    05277     // This scheme does not work if RtlInitializeCriticalSection() or NtCreateEvent fails - but in this case the
    05278     // caller has not choices left.
    05279
    05280     if (!InterlockedExchange(&StartedTimerInitialization, 1L)) {
    05281
    05282         if (CompletedTimerInitialization)
    05283             InterlockedExchange(&CompletedTimerInitialization, 0 ) ;
    05284
    05285         do {
    05286
    05287             // Initialize global timer lock
    05288
    05289             Status = RtlInitializeCriticalSection( &TimerCriticalSection ) ;
    05290             if (! NT_SUCCESS( Status )) {
    05291                 break ;
    05292             }
    05293
    05294             Status = NtCreateTimer(
    05295                                 &TimerHandle,
    05296                                 TIMER_ALL_ACCESS,
    05297                                 NULL,
    05298                                 NotificationTimer
    05299                                 ) ;
    05300
    05301             if (!NT_SUCCESS(Status) )
    05302                 break ;
    05303
    05304             InitializeListHead (&TimerQueues) ; // Initialize Timer Queue Structures
    05305
    05306
    05307             // initialize tick count
    05308
    05309             Resync64BitTickCount.QuadPart = NtGetTickCount()  ;
    05310             Firing64BitTickCount.QuadPart = 0 ;
    05311
    05312
    05313             Status = RtlpStartThreadFunc (RtlpTimerThread, &TimerThreadHandle) ;
    05314
    05315             if (!NT_SUCCESS(Status) )
    05316                 break ;
    05317
    05318
    05319         } while(FALSE ) ;
    05320
    05321         if (!NT_SUCCESS(Status) ) {
    05322
    05323             ASSERT (Status == STATUS_SUCCESS) ;
    05324
    05325             StartedTimerInitialization = 0 ;
    05326             InterlockedExchange (&CompletedTimerInitialization, ~0) ;
    05327
    05328             return Status ;
    05329         }
    05330
    05331         InterlockedExchange (&CompletedTimerInitialization, 1L) ;
    05332
    05333     } else {
    05334
    05335         // Sleep 1 ms and see if the other thread has completed initialization
    05336
    05337         ONE_MILLISECOND_TIMEOUT(TimeOut) ;
    05338
    05339         while (!(volatile ULONG) CompletedTimerInitialization) {
    05340
    05341             NtDelayExecution (FALSE, &TimeOut) ;
    05342
    05343         }
    05344
    05345         if (CompletedTimerInitialization != 1)
    05346             Status = STATUS_NO_MEMORY ;
    05347     }
    05348
    05349     return NT_SUCCESS(Status) ? STATUS_SUCCESS : Status ;
    05350 }

NTSTATUS RtlpInitializeWaitThreadPool | ( |  | ) |

Definition at line 2751 of file threads.c.

References ASSERT, CompletedWaitInitialization, FALSE, L, NT_SUCCESS, NtDelayExecution(), NTSTATUS(), ONE_MILLISECOND_TIMEOUT, RtlInitializeCriticalSection(), StartedWaitInitialization, Status, WaitCriticalSection, and WaitThreads.

Referenced by RtlRegisterWait().

    02755                    :
    02756
    02757     This routine initializes all aspects of the thread pool.
    02758
    02759 Arguments:
    02760
    02761     None
    02762
    02763 Return Value:
    02764
    02765     None
    02766
    02767 --*/
    02768 {
    02769     NTSTATUS Status = STATUS_SUCCESS;
    02770     LARGE_INTEGER TimeOut ;
    02771
    02772     // In order to avoid an explicit RtlInitialize() function to initialize the wait thread pool
    02773     // we use StartedWaitInitialization and CompletedWait Initialization to provide us the
    02774     // necessary synchronization to avoid multiple threads from initializing the thread pool.
    02775     // This scheme does not work if RtlInitializeCriticalSection() or NtCreateEvent fails - but in this case the
    02776     // caller has not choices left.
    02777
    02778     if (!InterlockedExchange(&StartedWaitInitialization, 1L)) {
    02779
    02780         if (CompletedWaitInitialization)
    02781             InterlockedExchange (&CompletedWaitInitialization, 0L) ;
    02782
    02783         // Initialize Critical Section
    02784
    02785         Status = RtlInitializeCriticalSection( &WaitCriticalSection ) ;
    02786
    02787         if (! NT_SUCCESS( Status ) ) {
    02788
    02789             ASSERT ( NT_SUCCESS( Status ) ) ;
    02790
    02791             StartedWaitInitialization = 0 ;
    02792             InterlockedExchange (&CompletedWaitInitialization, ~0) ;
    02793
    02794             return Status ;
    02795         }
    02796
    02797         InitializeListHead (&WaitThreads);  // Initialize global wait threads list
    02798
    02799         InterlockedExchange (&CompletedWaitInitialization, 1L) ;
    02800
    02801     } else {
    02802
    02803         // Sleep 1 ms and see if the other thread has completed initialization
    02804
    02805         ONE_MILLISECOND_TIMEOUT(TimeOut) ;
    02806
    02807         while (!(volatile ULONG) CompletedWaitInitialization) {
    02808
    02809             NtDelayExecution (FALSE, &TimeOut) ;
    02810
    02811         }
    02812
    02813         if (CompletedWaitInitialization != 1) {
    02814             Status = STATUS_NO_MEMORY ;
    02815         }
    02816     }
    02817
    02818     return Status ;
    02819 }

NTSTATUS RtlpInitializeWorkerThreadPool | ( |  | ) |

Definition at line 1965 of file threads.c.

References ASSERT, CompletedTimerInitialization, CompletedWorkerInitialization, FALSE, IOWorkerThreads, L, NT_SUCCESS, NtCreateIoCompletion(), NtDelayExecution(), NtQuerySystemInformation(), NTSTATUS(), NULL, ONE_MILLISECOND_TIMEOUT, RtlInitializeCriticalSection(), RtlpInitializeTimerThreadPool(), RtlpWorkerThreadInitializeTimers(), RtlQueueWorkItem(), StartedWorkerInitialization, Status, WorkerCompletionPort, WorkerCriticalSection, and WorkerThreadTimerQueueInit.

Referenced by RtlQueueWorkItem(), and RtlSetIoCompletionCallback().

    01969                    :
    01970
    01971     This routine initializes all aspects of the thread pool.
    01972
    01973 Arguments:
    01974
    01975     None
    01976
    01977 Return Value:
    01978
    01979     None
    01980
    01981 --*/
    01982 {
    01983     NTSTATUS Status = STATUS_SUCCESS ;
    01984     LARGE_INTEGER TimeOut ;
    01985
    01986
    01987     // Initialize the timer component if it hasnt been done already
    01988
    01989     if (CompletedTimerInitialization != 1) {
    01990
    01991         Status = RtlpInitializeTimerThreadPool () ;
    01992
    01993         if ( !NT_SUCCESS(Status) )
    01994             return Status ;
    01995
    01996     }
    01997
    01998
    01999     // In order to avoid an explicit RtlInitialize() function to initialize the thread pool
    02000     // we use StartedInitialization and CompletedInitialization to provide us the necessary
    02001     // synchronization to avoid multiple threads from initializing the thread pool.
    02002     // This scheme does not work if RtlInitializeCriticalSection() fails - but in this case the
    02003     // caller has no choices left.
    02004
    02005     if (!InterlockedExchange(&StartedWorkerInitialization, 1L)) {
    02006
    02007         if (CompletedWorkerInitialization)
    02008             InterlockedExchange( &CompletedWorkerInitialization, 0 ) ;
    02009
    02010
    02011         do {
    02012
    02013             // Initialize Critical Sections
    02014
    02015             Status = RtlInitializeCriticalSection( &WorkerCriticalSection );
    02016             if (!NT_SUCCESS(Status))
    02017                 break ;
    02018
    02019
    02020             InitializeListHead (&IOWorkerThreads) ;
    02021
    02022             {
    02023                 SYSTEM_BASIC_INFORMATION BasicInfo;
    02024
    02025                 // get number of processors
    02026
    02027                 Status = NtQuerySystemInformation (
    02028                                     SystemBasicInformation,
    02029                                     &BasicInfo,
    02030                                     sizeof(BasicInfo),
    02031                                     NULL
    02032                                     ) ;
    02033
    02034                 if ( !NT_SUCCESS(Status) ) {
    02035                     BasicInfo.NumberOfProcessors = 1 ;
    02036                 }
    02037
    02038                 // Create completion port used by worker threads
    02039
    02040                 Status = NtCreateIoCompletion (
    02041                                     &WorkerCompletionPort,
    02042                                     IO_COMPLETION_ALL_ACCESS,
    02043                                     NULL,
    02044                                     BasicInfo.NumberOfProcessors
    02045                                     );
    02046
    02047                 if (!NT_SUCCESS(Status))
    02048                     break ;
    02049
    02050             }
    02051
    02052         } while ( FALSE ) ;
    02053
    02054         if (!NT_SUCCESS(Status) ) {
    02055
    02056             ASSERT ( Status == STATUS_SUCCESS ) ;
    02057             StartedWorkerInitialization = 0 ;
    02058             InterlockedExchange( &CompletedWorkerInitialization, ~0 ) ;
    02059             return Status ;
    02060         }
    02061
    02062         // Signal that initialization has completed
    02063
    02064         InterlockedExchange (&CompletedWorkerInitialization, 1L) ;
    02065
    02066     } else {
    02067
    02068         LARGE_INTEGER Timeout ;
    02069
    02070         // Sleep 1 ms and see if the other thread has completed initialization
    02071
    02072         ONE_MILLISECOND_TIMEOUT(TimeOut) ;
    02073
    02074         while (!(volatile ULONG) CompletedWorkerInitialization) {
    02075
    02076             NtDelayExecution (FALSE, &TimeOut) ;
    02077         }
    02078
    02079         if (CompletedWorkerInitialization != 1)
    02080             return STATUS_NO_MEMORY ;
    02081
    02082     }
    02083
    02084
    02085     //
    02086     // create timer for worker thread. it should be created outside any worker
    02087     // lock and the above wait loop. It should not make the RtlpInitializeWorkerThread
    02088     // call blocking on a timer thread. so queue a work item.
    02089     //
    02090
    02091     if (NT_SUCCESS(Status)
    02092         && (InterlockedIncrement(&WorkerThreadTimerQueueInit) == 1) )
    02093     {
    02094         RtlQueueWorkItem(RtlpWorkerThreadInitializeTimers, NULL, 0);
    02095     }
    02096
    02097
    02098     return NT_SUCCESS(Status)  ? STATUS_SUCCESS : Status ;
    02099 }

BOOLEAN RtlpInsertInDeltaList | ( | PLIST_ENTRY | DeltaList,
|  | PRTLP_GENERIC_TIMER | NewTimer,
|  | ULONG | TimeRemaining,
|  | ULONG * | NewFiringTime
| ) |

Definition at line 4507 of file threads.c.

References _RTLP_GENERIC_TIMER::DeltaFiringTime, FALSE, _RTLP_GENERIC_TIMER::List, List, PRTLP_GENERIC_TIMER, RTLP_GENERIC_TIMER, and TRUE.

Referenced by RtlpAddTimer(), RtlpAddWait(), RtlpFireTimersAndReorder(), RtlpInsertTimersIntoDeltaList(), and RtlpReOrderDeltaList().

    04515                    :
    04516
    04517     Inserts the timer element in the appropriate place in the delta list.
    04518
    04519 Arguments:
    04520
    04521     DeltaList - Delta list to insert into
    04522
    04523     NewTimer - Timer element to insert into list
    04524
    04525     TimeRemaining - This time must be added to the head of the list to get "real"
    04526                     relative time.
    04527
    04528     NewFiringTime - If the new element was inserted at the head of the list - this
    04529                     will contain the new firing time in milliseconds. The caller
    04530                     can use this time to re-program the NT timer. This MUST NOT be
    04531                     changed if the function returns FALSE.
    04532
    04533 Return Value:
    04534
    04535     TRUE - If the timer was inserted at head of delta list
    04536
    04537     FALSE - otherwise
    04538
    04539 --*/
    04540 {
    04541     PLIST_ENTRY Node ;
    04542     PRTLP_GENERIC_TIMER Temp ;
    04543     PRTLP_GENERIC_TIMER Head ;
    04544
    04545     if (IsListEmpty (DeltaList)) {
    04546
    04547         InsertHeadList (DeltaList, &NewTimer->List) ;
    04548
    04549         *NewFiringTime = NewTimer->DeltaFiringTime ;
    04550
    04551         NewTimer->DeltaFiringTime = 0 ;
    04552
    04553         return TRUE ;
    04554
    04555     }
    04556
    04557     // Adjust the head of the list to reflect the time remaining on the NT timer
    04558
    04559     Head = CONTAINING_RECORD (DeltaList->Flink, RTLP_GENERIC_TIMER, List) ;
    04560
    04561     Head->DeltaFiringTime += TimeRemaining ;
    04562
    04563
    04564     // Find the appropriate location to insert this element in
    04565
    04566     for (Node = DeltaList->Flink ; Node != DeltaList ; Node = Node->Flink) {
    04567
    04568         Temp = CONTAINING_RECORD (Node, RTLP_GENERIC_TIMER, List) ;
    04569
    04570
    04571         if (Temp->DeltaFiringTime <= NewTimer->DeltaFiringTime) {
    04572
    04573             NewTimer->DeltaFiringTime -= Temp->DeltaFiringTime ;
    04574
    04575         } else {
    04576
    04577             // found appropriate place to insert this timer
    04578
    04579             break ;
    04580
    04581         }
    04582
    04583     }
    04584
    04585     // Either we have found the appopriate node to insert before in terms of deltas.
    04586     // OR we have come to the end of the list. Insert this timer here.
    04587
    04588     InsertHeadList (Node->Blink, &NewTimer->List) ;
    04589
    04590
    04591     // If this isnt the last element in the list - adjust the delta of the
    04592     // next element
    04593
    04594     if (Node != DeltaList) {
    04595
    04596         Temp->DeltaFiringTime -= NewTimer->DeltaFiringTime ;
    04597
    04598     }
    04599
    04600
    04601     // Check if element was inserted at head of list
    04602
    04603     if (DeltaList->Flink == &NewTimer->List) {
    04604
    04605         // Set NewFiringTime to the time in milliseconds when the new head of list
    04606         // should be serviced.
    04607
    04608         *NewFiringTime = NewTimer->DeltaFiringTime ;
    04609
    04610         // This means the timer must be programmed to service this request
    04611
    04612         NewTimer->DeltaFiringTime = 0 ;
    04613
    04614         return TRUE ;
    04615
    04616     } else {
    04617
    04618         // No change to the head of the list, set the delta time back
    04619
    04620         Head->DeltaFiringTime -= TimeRemaining ;
    04621
    04622         return FALSE ;
    04623
    04624     }
    04625
    04626 }

VOID RtlpInsertTimersIntoDeltaList | ( | IN PLIST_ENTRY | NewTimerList,
|  | IN PLIST_ENTRY | DeltaTimerList,
|  | IN ULONG | TimeRemaining,
|  | OUT ULONG * | NewFiringTime
| ) |

Definition at line 5146 of file threads.c.

References List, and RtlpInsertInDeltaList().

    05154                    :
    05155
    05156     This routine walks thru a list of timers in NewTimerList and inserts them into a delta
    05157     timers list pointed to by DeltaTimerList. The timeout associated with the first element
    05158     in the new list is returned in NewFiringTime.
    05159
    05160 Arguments:
    05161
    05162     NewTimerList - List of timers that need to be inserted into the DeltaTimerList
    05163
    05164     DeltaTimerList - Existing delta list of zero or more timers.
    05165
    05166     TimeRemaining - Firing time of the first element in the DeltaTimerList
    05167
    05168     NewFiringTime - Location where the new firing time will be returned
    05169
    05170 Return Value:
    05171
    05172
    05173 --*/
    05174 {
    05175     PRTLP_GENERIC_TIMER Timer ;
    05176     PLIST_ENTRY TNode ;
    05177     PLIST_ENTRY Temp ;
    05178
    05179     for (TNode = NewTimerList->Flink ; TNode != NewTimerList ; TNode = TNode->Flink) {
    05180
    05181         Temp = TNode->Blink ;
    05182
    05183         RemoveEntryList (Temp->Flink) ;
    05184
    05185         Timer = CONTAINING_RECORD (TNode, RTLP_GENERIC_TIMER, List) ;
    05186
    05187         if (RtlpInsertInDeltaList (DeltaTimerList, Timer, TimeRemaining, NewFiringTime)) {
    05188
    05189             TimeRemaining = *NewFiringTime ;
    05190
    05191         }
    05192
    05193         TNode = Temp ;
    05194
    05195     }
    05196
    05197 }

LONG RtlpIOWorkerThread | ( | PVOID | Initialized | ) |

Definition at line 2370 of file threads.c.

References ASSERT, FALSE, _RTLP_IOWORKER_TCB::Flags, Initialized, IOWORKER_IDLE_TIMEOUT, IOWorkerThreads, L, _RTLP_IOWORKER_TCB::List, _RTLP_IOWORKER_TCB::LongFunctionFlag, NEW_THREAD_THRESHOLD, NT_SUCCESS, NtClose(), NtDelayExecution(), NtDuplicateObject(), NtQueryInformationThread(), NTSTATUS(), NULL, NumIOWorkerThreads, NumIOWorkRequests, NumLongIOWorkRequests, RtlpExitThreadFunc, Status, _RTLP_IOWORKER_TCB::ThreadHandle, TRUE, and WorkerCriticalSection.

Referenced by RtlpStartIOWorkerThread().

    02375                    :
    02376
    02377     All I/O worker threads execute in this routine. All the work requests execute as APCs
    02378     in this thread.
    02379
    02380 Arguments:
    02381
    02382     Initialized - set to 1 when the initialization has completed
    02383
    02384 Return Value:
    02385
    02386 --*/
    02387 {
    02388     #define IOWORKER_IDLE_TIMEOUT     40000    // In Milliseconds
    02389
    02390     LARGE_INTEGER TimeOut ;
    02391     ULONG SleepTime = IOWORKER_IDLE_TIMEOUT ;
    02392     RTLP_IOWORKER_TCB ThreadCB ;    // Control Block allocated on the stack
    02393     NTSTATUS Status ;
    02394     BOOLEAN Terminate ;
    02395
    02396
    02397     //
    02398     // Initialize thread control block
    02399     // and insert it into list of IOWorker Threads
    02400     //
    02401
    02402     Status = NtDuplicateObject(
    02403                 NtCurrentProcess(),
    02404                 NtCurrentThread(),
    02405                 NtCurrentProcess(),
    02406                 &ThreadCB.ThreadHandle,
    02407                 0,
    02408                 FALSE,
    02409                 DUPLICATE_SAME_ACCESS
    02410                 ) ;
    02411
    02412     if (!NT_SUCCESS(Status)) {
    02413         ASSERT (FALSE) ;
    02414         InterlockedExchange ((ULONG *)Initialized, (ULONG)~0) ;
    02415         return STATUS_NO_MEMORY;
    02416     }
    02417
    02418     InsertHeadList (&IOWorkerThreads, &ThreadCB.List) ;
    02419     ThreadCB.Flags = 0 ;
    02420     ThreadCB.LongFunctionFlag = FALSE ;
    02421
    02422     InterlockedIncrement(&NumIOWorkerThreads) ;
    02423
    02424
    02425     // We are all initialized now. Notify the starter to queue the task.
    02426
    02427     InterlockedExchange ((ULONG *)Initialized, 1L) ;
    02428
    02429
    02430
    02431     // Sleep alertably so that all the activity can take place
    02432     // in APCs
    02433
    02434     for ( ; ; ) {
    02435
    02436         // Set timeout for IdleTimeout
    02437
    02438         TimeOut.QuadPart = Int32x32To64( SleepTime, -10000 ) ;
    02439
    02440
    02441         Status = NtDelayExecution (TRUE, &TimeOut) ;
    02442
    02443
    02444         // Status is STATUS_SUCCESS only when it has timed out
    02445
    02446         if (Status != STATUS_SUCCESS) {
    02447             continue ;
    02448         }
    02449
    02450
    02451         //
    02452         // idle timeout. check if you can terminate the thread
    02453         //
    02454
    02455         Terminate = FALSE ;
    02456
    02457         RtlEnterCriticalSection (&WorkerCriticalSection) ;
    02458
    02459
    02460         // dont terminate if it is a persistent thread
    02461
    02462         if (ThreadCB.Flags & WT_EXECUTEINPERSISTENTIOTHREAD) {
    02463
    02464             TimeOut.LowPart = 0x0;
    02465             TimeOut.HighPart = 0x80000000;
    02466
    02467             RtlLeaveCriticalSection (&WorkerCriticalSection) ;
    02468
    02469             continue ;
    02470         }
    02471
    02472
    02473         // The thread terminates if there are > 1 threads and the queue is small
    02474         // OR if there is only 1 thread and there is no request pending
    02475
    02476         if (NumIOWorkerThreads >  1) {
    02477
    02478
    02479             ULONG NumEffIOWorkerThreads = NumIOWorkerThreads - NumLongIOWorkRequests ;
    02480             ULONG Threshold ;
    02481
    02482             if (NumEffIOWorkerThreads == 0) {
    02483
    02484                 Terminate = FALSE ;
    02485
    02486             } else {
    02487
    02488                 // Check if we need to shrink worker thread pool
    02489
    02490                 Threshold = NEW_THREAD_THRESHOLD * (NumEffIOWorkerThreads-1);
    02491
    02492
    02493
    02494                 if  (NumIOWorkRequests-NumLongIOWorkRequests < Threshold)  {
    02495
    02496                     Terminate = TRUE ;
    02497
    02498                 } else {
    02499
    02500                     Terminate = FALSE ;
    02501                     SleepTime <<= 1 ;
    02502                 }
    02503             }
    02504
    02505         } else {
    02506
    02507             if (NumIOWorkRequests == 0) {
    02508
    02509                 // delay termination of last thread
    02510
    02511                 if (SleepTime < 4*IOWORKER_IDLE_TIMEOUT) {
    02512
    02513                     SleepTime <<= 1 ;
    02514                     Terminate = FALSE ;
    02515
    02516                 } else {
    02517
    02518                     Terminate = TRUE ;
    02519                 }
    02520
    02521             } else {
    02522
    02523                 Terminate = FALSE ;
    02524
    02525             }
    02526
    02527         }
    02528
    02529         //
    02530         // terminate only if no io is pending
    02531         //
    02532
    02533         if (Terminate) {
    02534
    02535             NTSTATUS Status;
    02536             THREAD_BASIC_INFORMATION ThreadInfo;
    02537             ULONG IsIoPending ;
    02538
    02539             Terminate = FALSE ;
    02540
    02541             Status = NtQueryInformationThread( ThreadCB.ThreadHandle,
    02542                                                ThreadIsIoPending,
    02543                                                &IsIoPending,
    02544                                                sizeof( IsIoPending ),
    02545                                                NULL
    02546                                              );
    02547             if (NT_SUCCESS( Status )) {
    02548
    02549                 if (! IsIoPending )
    02550                     Terminate = TRUE ;
    02551             }
    02552         }
    02553
    02554         if (Terminate) {
    02555
    02556             InterlockedDecrement (&NumIOWorkerThreads) ;
    02557
    02558             RemoveEntryList (&ThreadCB.List) ;
    02559             NtClose( ThreadCB.ThreadHandle ) ;
    02560
    02561             RtlLeaveCriticalSection (&WorkerCriticalSection) ;
    02562
    02563             RtlpExitThreadFunc( 0 );
    02564
    02565         } else {
    02566
    02567             // This is the condition where a request was queued *after* the
    02568             // thread woke up - ready to terminate because of inactivity. In
    02569             // this case dont terminate - service the completion port.
    02570
    02571             RtlLeaveCriticalSection (&WorkerCriticalSection) ;
    02572
    02573         }
    02574     }
    02575
    02576     return 0 ;  // Keep compiler happy
    02577
    02578 }

VOID RtlpProcessTimeouts | ( | PRTLP_WAIT_THREAD_CONTROL_BLOCK | ThreadCB | ) |

Definition at line 3697 of file threads.c.

References _RTLP_WAIT_THREAD_CONTROL_BLOCK::Current64BitTickCount, _RTLP_WAIT_THREAD_CONTROL_BLOCK::Firing64BitTickCount, RtlpFireTimers(), RtlpFireTimersAndReorder(), RtlpGet64BitTickCount(), RtlpGetTimeRemaining(), RtlpResetTimer(), _RTLP_WAIT_THREAD_CONTROL_BLOCK::TimerHandle, and _RTLP_WAIT_THREAD_CONTROL_BLOCK::TimerQueue.

Referenced by RtlpWaitThread().

    03702                    :
    03703
    03704     This routine processes timeouts for the wait thread
    03705
    03706 Arguments:
    03707
    03708     ThreadCB - The wait thread to add the wait to
    03709
    03710 Return Value:
    03711
    03712 --*/
    03713 {
    03714     ULONG NewFiringTime, TimeRemaining ;
    03715     LIST_ENTRY TimersToFireList ;
    03716
    03717     //
    03718     // check if incorrect timer fired
    03719     //
    03720     if (ThreadCB->Firing64BitTickCount >
    03721             RtlpGet64BitTickCount(&ThreadCB->Current64BitTickCount) + 200 )
    03722     {
    03723         RtlpResetTimer (ThreadCB->TimerHandle,
    03724                     RtlpGetTimeRemaining (ThreadCB->TimerHandle),
    03725                     ThreadCB) ;
    03726
    03727         return ;
    03728     }
    03729
    03730     InitializeListHead( &TimersToFireList ) ;
    03731
    03732
    03733     // Walk thru the timer list and fire all waits with DeltaFiringTime == 0
    03734
    03735     RtlpFireTimersAndReorder (&ThreadCB->TimerQueue, &NewFiringTime, &TimersToFireList) ;
    03736
    03737     // Reset the NT timer
    03738
    03739     RtlpResetTimer (ThreadCB->TimerHandle, NewFiringTime, ThreadCB) ;
    03740
    03741
    03742     RtlpFireTimers( &TimersToFireList ) ;
    03743 }

VOID RtlpProcessWaitCompletion | ( | PRTLP_WAIT | Wait,
|  | ULONG | ArrayIndex
| ) |

Definition at line 3172 of file threads.c.

References _RTLP_WAIT_THREAD_CONTROL_BLOCK::ActiveWaitArray, _RTLP_WAIT_THREAD_CONTROL_BLOCK::ActiveWaitPointers, _RTLP_WAIT::Context, DBG_SET_FUNCTION, DbgPrint, DPRN4, FALSE, _RTLP_WAIT::Flags, _RTLP_WAIT::Function, NT_SUCCESS, NTSTATUS(), _RTLP_WAIT_THREAD_CONTROL_BLOCK::NumActiveWaits, _RTLP_GENERIC_TIMER::Period, _RTLP_WAIT::RefCount, RTLP_ASYNC_CALLBACK, RtlpAsyncCallbackCompletion(), RtlpDeactivateWait(), RtlpDeleteWait(), RtlpForceAllocateTPHeap(), RtlpFreeTPHeap, RtlpGetTimeRemaining(), RtlpReOrderDeltaList(), RtlpResetTimer(), RtlpShiftWaitArray, RtlQueueWorkItem(), Status, _RTLP_WAIT::ThreadCB, _RTLP_WAIT::Timer, _RTLP_WAITWORKER::TimerCondition, _RTLP_WAIT_THREAD_CONTROL_BLOCK::TimerHandle, _RTLP_WAIT_THREAD_CONTROL_BLOCK::TimerQueue, TRUE, _RTLP_WAITWORKER::Wait, and _RTLP_WAITWORKER::WaitThreadCallback.

Referenced by RtlpWaitThread().

    03178                    :
    03179
    03180     This routine is used for processing a completed wait
    03181
    03182 Arguments:
    03183
    03184     Wait - Wait that completed
    03185
    03186 Return Value:
    03187
    03188 --*/
    03189 {
    03190     ULONG TimeRemaining ;
    03191     ULONG NewFiringTime ;
    03192     LARGE_INTEGER DueTime ;
    03193     PRTLP_WAIT_THREAD_CONTROL_BLOCK ThreadCB ;
    03194     PRTLP_ASYNC_CALLBACK AsyncCallback ;
    03195
    03196     ThreadCB = Wait->ThreadCB ;
    03197
    03198     // deactivate wait if it is meant for single execution
    03199
    03200     if ( Wait->Flags & WT_EXECUTEONLYONCE ) {
    03201
    03202         RtlpDeactivateWait (Wait) ;
    03203     }
    03204
    03205     else {
    03206         // if wait being reactivated, then reset the timer now itself as
    03207         // it can be deleted in the callback function
    03208
    03209         if  ( Wait->Timer ) {
    03210
    03211             TimeRemaining = RtlpGetTimeRemaining (ThreadCB->TimerHandle) ;
    03212
    03213             if (RtlpReOrderDeltaList (
    03214                         &ThreadCB->TimerQueue.TimerList,
    03215                         Wait->Timer,
    03216                         TimeRemaining,
    03217                         &NewFiringTime,
    03218                         Wait->Timer->Period)) {
    03219
    03220                 // There is a new element at the head of the queue we need to reset the NT
    03221                 // timer to fire later
    03222
    03223                 RtlpResetTimer (ThreadCB->TimerHandle, NewFiringTime, ThreadCB) ;
    03224             }
    03225
    03226         }
    03227
    03228         // move the wait entry to the end, and shift elements to its right one pos towards left
    03229         {
    03230             HANDLE HandlePtr = ThreadCB->ActiveWaitArray[ArrayIndex];
    03231             PRTLP_WAIT WaitPtr = ThreadCB->ActiveWaitPointers[ArrayIndex];
    03232
    03233             RtlpShiftWaitArray(ThreadCB, ArrayIndex+1, ArrayIndex,
    03234                             ThreadCB->NumActiveWaits -1 - ArrayIndex)
    03235             ThreadCB->ActiveWaitArray[ThreadCB->NumActiveWaits-1] = HandlePtr ;
    03236             ThreadCB->ActiveWaitPointers[ThreadCB->NumActiveWaits-1] = WaitPtr ;
    03237         }
    03238     }
    03239
    03240     // call callback function (FALSE since this isnt a timeout related callback)
    03241
    03242     if ( Wait->Flags & WT_EXECUTEINWAITTHREAD ) {
    03243
    03244         // executing callback after RtlpDeactivateWait allows the Callback to call
    03245         // RtlDeregisterWait Wait->RefCount is not incremented so that RtlDeregisterWait
    03246         // will work on this Wait. Though Wait->RefCount is not incremented, others cannot
    03247         // deregister this Wait as it has to be queued as an APC.
    03248
    03249         if (DPRN4)
    03250         DbgPrint("Calling WaitOrTimer(wait): fn:%x  context:%x  bool:%d Thread<%d:%d>\n",
    03251                 (ULONG_PTR)Wait->Function, (ULONG_PTR)Wait->Context,
    03252                 FALSE,
    03253                 HandleToUlong(NtCurrentTeb()->ClientId.UniqueThread),
    03254                 HandleToUlong(NtCurrentTeb()->ClientId.UniqueProcess)
    03255                 ) ;
    03256
    03257         #if (DBG1)
    03258         DBG_SET_FUNCTION( Wait->Function, Wait->Context ) ;
    03259         #endif
    03260
    03261
    03262         ((WAITORTIMERCALLBACKFUNC)(Wait->Function))(Wait->Context, FALSE) ;
    03263
    03264
    03265         // Wait object could have been deleted in the above callback
    03266
    03267         return ;
    03268
    03269
    03270     } else {
    03271
    03272         AsyncCallback = RtlpForceAllocateTPHeap( sizeof( RTLP_ASYNC_CALLBACK ), 0 );
    03273
    03274         if ( AsyncCallback ) {
    03275
    03276             NTSTATUS Status;
    03277
    03278             AsyncCallback->Wait = Wait ;
    03279             AsyncCallback->WaitThreadCallback = TRUE ;
    03280             AsyncCallback->TimerCondition = FALSE ;
    03281
    03282             InterlockedIncrement( &Wait->RefCount ) ;
    03283
    03284             Status = RtlQueueWorkItem( RtlpAsyncCallbackCompletion, AsyncCallback,
    03285                                 Wait->Flags );
    03286
    03287
    03288             if (!NT_SUCCESS(Status)) {
    03289
    03290                 RtlpFreeTPHeap( AsyncCallback );
    03291
    03292                 if ( InterlockedDecrement( &Wait->RefCount ) == 0 ) {
    03293                     RtlpDeleteWait( Wait ) ;
    03294                 }
    03295             }
    03296         }
    03297     }
    03298 }

NTSTATUS RtlpQueueIOWorkerRequest | ( | WORKERCALLBACKFUNC | Function,
|  | PVOID | Context,
|  | ULONG | Flags
| ) |

Definition at line 1638 of file threads.c.

References DbgPrint, FALSE, _RTLP_IOWORKER_TCB::Flags, IOWorkerThreads, List, _RTLP_IOWORKER_TCB::List, _RTLP_IOWORKER_TCB::LongFunctionFlag, NT_SUCCESS, NtQueueApcThread(), NTSTATUS(), NumIOWorkerThreads, NumIOWorkRequests, NumLongIOWorkRequests, PersistentIOTCB, RtlpExecuteIOWorkItem(), Status, _RTLP_IOWORKER_TCB::ThreadHandle, and TRUE.

Referenced by RtlQueueWorkItem().

    01646                    :
    01647
    01648     This routine queues up the request to be executed in an IO worker thread.
    01649
    01650 Arguments:
    01651
    01652     Function - Routine that is called by the worker thread
    01653
    01654     Context - Opaque pointer passed in as an argument to WorkerProc
    01655
    01656 Return Value:
    01657
    01658 --*/
    01659
    01660 {
    01661     NTSTATUS Status ;
    01662     PRTLP_IOWORKER_TCB TCB ;
    01663     BOOLEAN LongFunction = (Flags & WT_EXECUTELONGFUNCTION) ? TRUE : FALSE ;
    01664     PLIST_ENTRY  ple ;
    01665
    01666
    01667     if (Flags & WT_EXECUTEINPERSISTENTIOTHREAD) {
    01668
    01669         if (!PersistentIOTCB) {
    01670             for (ple=IOWorkerThreads.Flink;  ple!=&IOWorkerThreads;  ple=ple->Flink) {
    01671                 TCB = CONTAINING_RECORD (ple, RTLP_IOWORKER_TCB, List) ;
    01672                 if (! TCB->LongFunctionFlag)
    01673                     break;
    01674             }
    01675
    01676             if (ple == &IOWorkerThreads) {
    01677                 // ASSERT(FALSE);
    01678                 return STATUS_NO_MEMORY;
    01679             }
    01680
    01681
    01682             PersistentIOTCB = TCB ;
    01683             TCB->Flags |= WT_EXECUTEINPERSISTENTIOTHREAD ;
    01684
    01685         } else {
    01686             TCB = PersistentIOTCB ;
    01687         }
    01688
    01689     } else {
    01690         for (ple=IOWorkerThreads.Flink;  ple!=&IOWorkerThreads;  ple=ple->Flink) {
    01691
    01692             TCB = CONTAINING_RECORD (ple, RTLP_IOWORKER_TCB, List) ;
    01693
    01694             // do not queue to the thread if it is executing a long function, or
    01695             // if you are queueing a long function and the thread is a persistent thread
    01696
    01697             if (! TCB->LongFunctionFlag
    01698                 && (! ((TCB->Flags&WT_EXECUTEINPERSISTENTIOTHREAD)
    01699                         && (Flags&WT_EXECUTELONGFUNCTION)))) {
    01700                 break ;
    01701             }
    01702
    01703         }
    01704
    01705         if ((ple == &IOWorkerThreads) && (NumIOWorkerThreads<1)) {
    01706
    01707             #if DBG
    01708             DbgPrint("ThreadPool:ntdll.dll: Out of memory. "
    01709                      "Could not execute IOWorkItem(%x)\n", (ULONG_PTR)Function);
    01710             #endif
    01711
    01712             return STATUS_NO_MEMORY;
    01713         }
    01714         else {
    01715             ple = IOWorkerThreads.Flink;
    01716             TCB = CONTAINING_RECORD (ple, RTLP_IOWORKER_TCB, List) ;
    01717
    01718             // treat it as a short function so that counters work fine.
    01719
    01720             LongFunction = FALSE;
    01721         }
    01722
    01723         // In order to implement "fair" assignment of work items between IO worker threads
    01724         // each time remove the entry and reinsert at back.
    01725
    01726         RemoveEntryList (&TCB->List) ;
    01727         InsertTailList (&IOWorkerThreads, &TCB->List) ;
    01728     }
    01729
    01730
    01731     // Increment the outstanding work request counter
    01732
    01733     InterlockedIncrement (&NumIOWorkRequests) ;
    01734     if (LongFunction) {
    01735         InterlockedIncrement( &NumLongIOWorkRequests ) ;
    01736         TCB->LongFunctionFlag = TRUE ;
    01737     }
    01738
    01739     // Queue an APC to the IoWorker Thread
    01740
    01741     Status = NtQueueApcThread(
    01742                     TCB->ThreadHandle,
    01743                     LongFunction? (PPS_APC_ROUTINE)RtlpExecuteLongIOWorkItem:
    01744                                   (PPS_APC_ROUTINE)RtlpExecuteIOWorkItem,
    01745                     (PVOID)Function,
    01746                     Context,
    01747                     TCB
    01748                     );
    01749
    01750     if (! NT_SUCCESS( Status ) ) {
    01751         InterlockedDecrement( &NumIOWorkRequests ) ;
    01752         if (LongFunction)
    01753             InterlockedDecrement( &NumLongIOWorkRequests ) ;
    01754     }
    01755
    01756     return Status ;
    01757
    01758 }

NTSTATUS RtlpQueueWorkerRequest | ( | WORKERCALLBACKFUNC | Function,
|  | PVOID | Context,
|  | ULONG | Flags
| ) |

Definition at line 1506 of file threads.c.

References ASSERT, DbgPrint, FALSE, _RTLP_WORK::Flags, _RTLP_WORK::Function, NT_SUCCESS, NtQueueApcThread(), NtSetIoCompletion(), NTSTATUS(), NumLongWorkRequests, NumWorkRequests, PRTLP_WORK, RTLP_WORK, RtlpExecuteWorkerRequest(), RtlpForceAllocateTPHeap(), RtlpFreeTPHeap, Status, TimerThreadHandle, and WorkerCompletionPort.

Referenced by RtlQueueWorkItem().

    01513                    :
    01514
    01515     This routine queues up the request to be executed in a worker thread.
    01516
    01517 Arguments:
    01518
    01519     Function - Routine that is called by the worker thread
    01520
    01521     Context - Opaque pointer passed in as an argument to WorkerProc
    01522
    01523     Flags - flags passed to RtlQueueWorkItem
    01524
    01525 Return Value:
    01526
    01527 --*/
    01528
    01529 {
    01530     NTSTATUS Status ;
    01531     PRTLP_WORK WorkEntry ;
    01532
    01533     // Increment the outstanding work request counter
    01534
    01535     InterlockedIncrement (&NumWorkRequests) ;
    01536     if (Flags & WT_EXECUTELONGFUNCTION) {
    01537         InterlockedIncrement( & NumLongWorkRequests ) ;
    01538     }
    01539
    01540     WorkEntry = (PRTLP_WORK) RtlpForceAllocateTPHeap ( sizeof (RTLP_WORK),
    01541                                                         HEAP_ZERO_MEMORY) ;
    01542     WorkEntry->Function = Function ;
    01543     WorkEntry->Flags = Flags ;
    01544
    01545     if (Flags & WT_EXECUTEINPERSISTENTTHREAD) {
    01546
    01547         // Queue APC to timer thread
    01548
    01549         Status = NtQueueApcThread(
    01550                         TimerThreadHandle,
    01551                         (PPS_APC_ROUTINE)RtlpExecuteWorkerRequest,
    01552                         (PVOID) STATUS_SUCCESS,
    01553                         (PVOID) Context,
    01554                         (PVOID) WorkEntry
    01555                         ) ;
    01556
    01557     } else {
    01558
    01559         Status = NtSetIoCompletion (
    01560                     WorkerCompletionPort,
    01561                     RtlpExecuteWorkerRequest,
    01562                     (PVOID) WorkEntry,
    01563                     STATUS_SUCCESS,
    01564                     (ULONG_PTR)Context
    01565                     );
    01566     }
    01567
    01568     if ( ! NT_SUCCESS(Status) ) {
    01569
    01570         InterlockedDecrement (&NumWorkRequests) ;
    01571         if (Flags && WT_EXECUTELONGFUNCTION) {
    01572             InterlockedDecrement( &NumLongWorkRequests ) ;
    01573         }
    01574
    01575         RtlpFreeTPHeap( WorkEntry ) ;
    01576
    01577         ASSERT(FALSE) ;
    01578
    01579         #if DBG
    01580         DbgPrint("ERROR!! Thread Pool (RtlQeueuWorkItem): could not queue work item\n");
    01581         #endif
    01582     }
    01583
    01584     return Status ;
    01585 }

BOOLEAN RtlpRemoveFromDeltaList | ( | PLIST_ENTRY | DeltaList,
|  | PRTLP_GENERIC_TIMER | Timer,
|  | ULONG | TimeRemaining,
|  | ULONG * | NewFiringTime
| ) |

Definition at line 4631 of file threads.c.

References _RTLP_GENERIC_TIMER::DeltaFiringTime, FALSE, INFINITE_TIME, _RTLP_GENERIC_TIMER::List, List, and TRUE.

Referenced by RtlpDeactivateTimer(), RtlpDeactivateWait(), RtlpDeleteTimerQueue(), and RtlpReOrderDeltaList().

    04639                    :
    04640
    04641     Removes the specified timer from the delta list
    04642
    04643 Arguments:
    04644
    04645     DeltaList - Delta list to insert into
    04646
    04647     Timer - Timer element to insert into list
    04648
    04649     TimerHandle - Handle of the NT Timer object
    04650
    04651     TimeRemaining - This time must be added to the head of the list to get "real"
    04652                     relative time.
    04653
    04654 Return Value:
    04655
    04656     TRUE if the timer was removed from head of timer list
    04657     FALSE otherwise
    04658
    04659 --*/
    04660 {
    04661     PLIST_ENTRY Next ;
    04662     PRTLP_GENERIC_TIMER Temp ;
    04663
    04664     Next = Timer->List.Flink ;
    04665
    04666     RemoveEntryList (&Timer->List) ;
    04667
    04668     if (IsListEmpty (DeltaList)) {
    04669
    04670         *NewFiringTime = INFINITE_TIME ;
    04671
    04672         return TRUE ;
    04673
    04674     }
    04675
    04676     if (Next == DeltaList)  {
    04677
    04678         // If we removed the last element in the list nothing to do either
    04679
    04680         return FALSE ;
    04681
    04682     } else {
    04683
    04684         Temp = CONTAINING_RECORD ( Next, RTLP_GENERIC_TIMER, List) ;
    04685
    04686         Temp->DeltaFiringTime += Timer->DeltaFiringTime ;
    04687
    04688         // Check if element was removed from head of list
    04689
    04690         if (DeltaList->Flink == Next) {
    04691
    04692             *NewFiringTime = Temp->DeltaFiringTime + TimeRemaining ;
    04693
    04694             Temp->DeltaFiringTime = 0 ;
    04695
    04696             return TRUE ;
    04697
    04698         } else {
    04699
    04700             return FALSE ;
    04701
    04702         }
    04703
    04704     }
    04705
    04706 }

BOOLEAN RtlpReOrderDeltaList | ( | PLIST_ENTRY | DeltaList,
|  | PRTLP_GENERIC_TIMER | Timer,
|  | ULONG | TimeRemaining,
|  | ULONG * | NewFiringTime,
|  | ULONG | ChangedFiringTime
| ) |

Definition at line 4711 of file threads.c.

References _RTLP_GENERIC_TIMER::DeltaFiringTime, RtlpInsertInDeltaList(), RtlpRemoveFromDeltaList(), and TRUE.

Referenced by RtlpAddTimer(), RtlpDeactivateTimer(), RtlpProcessWaitCompletion(), and RtlpUpdateTimer().

    04720                    :
    04721
    04722     Called when a timer in the delta list needs to be re-inserted because the firing time
    04723     has changed.
    04724
    04725 Arguments:
    04726
    04727     DeltaList - List in which to re-insert
    04728
    04729     Timer - Timer for which the firing time has changed
    04730
    04731     TimeRemaining - Time before the head of the delta list is fired
    04732
    04733     NewFiringTime - If the new element was inserted at the head of the list - this
    04734                     will contain the new firing time in milliseconds. The caller
    04735                     can use this time to re-program the NT timer.
    04736
    04737     ChangedFiringTime - Changed Time for the specified timer.
    04738
    04739 Return Value:
    04740
    04741     TRUE if the timer was removed from head of timer list
    04742     FALSE otherwise
    04743
    04744 --*/
    04745 {
    04746     ULONG NewTimeRemaining ;
    04747     PRTLP_GENERIC_TIMER Temp ;
    04748
    04749     // Remove the timer from the list
    04750
    04751     if (RtlpRemoveFromDeltaList (DeltaList, Timer, TimeRemaining, NewFiringTime)) {
    04752
    04753         // If element was removed from the head of the list we should record that
    04754
    04755         NewTimeRemaining = *NewFiringTime ;
    04756
    04757
    04758     } else {
    04759
    04760         // Element was not removed from head of delta list, the current TimeRemaining is valid
    04761
    04762         NewTimeRemaining = TimeRemaining ;
    04763
    04764     }
    04765
    04766     // Before inserting Timer, set its delta time to the ChangedFiringTime
    04767
    04768     Timer->DeltaFiringTime = ChangedFiringTime ;
    04769
    04770     // Reinsert this element back in the list
    04771
    04772     if (!RtlpInsertInDeltaList (DeltaList, Timer, NewTimeRemaining, NewFiringTime)) {
    04773
    04774         // If we did not add at the head of the list, then we should return TRUE if
    04775         // RtlpRemoveFromDeltaList() had returned TRUE. We also update the NewFiringTime to
    04776         // the reflect the new firing time returned by RtlpRemoveFromDeltaList()
    04777
    04778         *NewFiringTime = NewTimeRemaining ;
    04779
    04780         return (NewTimeRemaining != TimeRemaining) ;
    04781
    04782     } else {
    04783
    04784         // NewFiringTime contains the time the NT timer must be programmed for
    04785
    04786         return TRUE ;
    04787
    04788     }
    04789
    04790 }

VOID RtlpResetTimer | ( | HANDLE | TimerHandle,
|  | ULONG | DueTime,
|  | PRTLP_WAIT_THREAD_CONTROL_BLOCK | ThreadCB
| ) |

Definition at line 4429 of file threads.c.

References _RTLP_WAIT_THREAD_CONTROL_BLOCK::Current64BitTickCount, FALSE, _RTLP_WAIT_THREAD_CONTROL_BLOCK::Firing64BitTickCount, INFINITE_TIME, Last64BitTickCount, NtCancelTimer(), NtSetTimer(), NULL, RtlpGet64BitTickCount(), RtlpGetResync64BitTickCount, RtlpServiceTimer(), RtlpSetFiring64BitTickCount, and TimerHandle.

Referenced by RtlpAddTimer(), RtlpAddWait(), RtlpDeactivateTimer(), RtlpDeactivateWait(), RtlpDeleteTimerQueue(), RtlpProcessTimeouts(), RtlpProcessWaitCompletion(), RtlpServiceTimer(), RtlpTimerThread(), RtlpUpdateTimer(), and RtlpWaitThread().

    04436                    :
    04437
    04438     This routine resets the timer object with the new due time.
    04439
    04440 Arguments:
    04441
    04442     TimerHandle - Handle to the timer object
    04443
    04444     DueTime - Relative timer due time in Milliseconds
    04445
    04446 Return Value:
    04447
    04448 --*/
    04449 {
    04450     LARGE_INTEGER LongDueTime ;
    04451
    04452     NtCancelTimer (TimerHandle, NULL) ;
    04453
    04454     // If the DueTime is INFINITE_TIME then set the timer to the largest integer possible
    04455
    04456     if (DueTime == INFINITE_TIME) {
    04457
    04458         LongDueTime.LowPart = 0x0 ;
    04459
    04460         LongDueTime.HighPart = 0x80000000 ;
    04461
    04462     } else {
    04463
    04464         //
    04465         // set the absolute time when timer is to be fired
    04466         //
    04467
    04468         if (ThreadCB) {
    04469
    04470             ThreadCB->Firing64BitTickCount = DueTime
    04471                                 + RtlpGet64BitTickCount(&ThreadCB->Current64BitTickCount) ;
    04472
    04473         } else {
    04474             //
    04475             // adjust for drift only if it is a global timer
    04476             //
    04477
    04478             ULONG Drift ;
    04479             LONGLONG llCurrentTick ;
    04480
    04481             llCurrentTick = RtlpGet64BitTickCount(&Last64BitTickCount) ;
    04482
    04483             Drift = (ULONG) (llCurrentTick - RtlpGetResync64BitTickCount()) ;
    04484             DueTime = (DueTime > Drift) ? DueTime-Drift : 1 ;
    04485             RtlpSetFiring64BitTickCount(llCurrentTick + DueTime) ;
    04486         }
    04487
    04488
    04489         LongDueTime.QuadPart = Int32x32To64( DueTime, -10000 );
    04490
    04491     }
    04492
    04493
    04494     NtSetTimer (
    04495         TimerHandle,
    04496         &LongDueTime,
    04497         ThreadCB ? NULL : RtlpServiceTimer,
    04498         NULL,
    04499         FALSE,
    04500         0,
    04501         NULL
    04502         ) ;
    04503 }

__inline LONGLONG RtlpResync64BitTickCount | ( |  | ) |

Definition at line 3674 of file threads.c.

References Last64BitTickCount, Resync64BitTickCount, and RtlpGet64BitTickCount().

Referenced by RtlDebugPrintTimes(), RtlpAddTimer(), RtlpCancelTimerEx(), RtlpDeleteTimerQueue(), RtlpServiceTimer(), and RtlpUpdateTimer().

    03678                    :
    03679
    03680     This routine is used for getting the latest 64bit tick count.
    03681
    03682 Arguments:
    03683
    03684 Return Value: 64bit tick count
    03685
    03686 Remarks: This call should be made in the first line of any APC queued
    03687     to the timer thread and nowhere else. It is used to reduce the drift
    03688
    03689 --*/
    03690 {
    03691     return Resync64BitTickCount.QuadPart =
    03692                     RtlpGet64BitTickCount(&Last64BitTickCount);
    03693 }

VOID RtlpServiceTimer | ( | PVOID | NotUsedArg,
|  | ULONG | NotUsedLowTimer,
|  | LONG | NotUsedHighTimer
| ) |

Definition at line 4821 of file threads.c.

References ACQUIRE_GLOBAL_TIMER_LOCK, DbgPrint, DPRN2, DPRN3, Firing64BitTickCount, INFINITE_TIME, Last64BitTickCount, List, NULL, PRTLP_TIMER, PRTLP_TIMER_QUEUE, RELEASE_GLOBAL_TIMER_LOCK, RtlDebugPrintTimes(), RTLP_TIMER_QUEUE, RtlpFireTimers(), RtlpFireTimersAndReorder(), RtlpGet64BitTickCount(), RtlpGetTimeRemaining(), RtlpInsertTimersIntoDeltaList(), RtlpResetTimer(), RtlpResync64BitTickCount(), TimerHandle, and TimerQueues.

Referenced by RtlpResetTimer().

    04828                    :
    04829
    04830     Services the timer. Runs in an APC.
    04831
    04832 Arguments:
    04833
    04834     NotUsedArg - Argument is not used in this function.
    04835
    04836     NotUsedLowTimer - Argument is not used in this function.
    04837
    04838     NotUsedHighTimer - Argument is not used in this function.
    04839
    04840 Return Value:
    04841
    04842 Remarks:
    04843     This APC is called only for timeouts of timer threads.
    04844
    04845 --*/
    04846 {
    04847     PRTLP_TIMER Timer ;
    04848     PRTLP_TIMER_QUEUE Queue ;
    04849     PLIST_ENTRY TNode ;
    04850     PLIST_ENTRY QNode ;
    04851     PLIST_ENTRY Temp ;
    04852     ULONG NewFiringTime ;
    04853     LIST_ENTRY ReinsertTimerQueueList ;
    04854     LIST_ENTRY TimersToFireList ;
    04855
    04856     RtlpResync64BitTickCount() ;
    04857
    04858     if (DPRN2) {
    04859         DbgPrint("Before service timer ThreadId<%x:%x>\n",
    04860                     HandleToUlong(NtCurrentTeb()->ClientId.UniqueThread),
    04861                     HandleToUlong(NtCurrentTeb()->ClientId.UniqueProcess));
    04862         RtlDebugPrintTimes ();
    04863     }
    04864
    04865     ACQUIRE_GLOBAL_TIMER_LOCK();
    04866
    04867     // fire it if it even 200ms ahead. else reset the timer
    04868
    04869     if (Firing64BitTickCount.QuadPart > RtlpGet64BitTickCount(&Last64BitTickCount) + 200) {
    04870
    04871         RtlpResetTimer (TimerHandle, RtlpGetTimeRemaining (TimerHandle), NULL) ;
    04872
    04873         RELEASE_GLOBAL_TIMER_LOCK() ;
    04874         return ;
    04875     }
    04876
    04877     InitializeListHead (&ReinsertTimerQueueList) ;
    04878
    04879     InitializeListHead (&TimersToFireList) ;
    04880
    04881
    04882     // We run thru all queues with DeltaFiringTime == 0 and fire all timers that
    04883     // have DeltaFiringTime == 0. We remove the fired timers and either free them
    04884     // (for one shot timers) or put them in aside list (for periodic timers).
    04885     // After we have finished firing all timers in a queue we reinsert the timers
    04886     // in the aside list back into the queue based on their new firing times.
    04887     //
    04888     // Similarly, we remove each fired Queue and put it in a aside list. After firing
    04889     // all queues with DeltaFiringTime == 0, we reinsert the Queues in the aside list
    04890     // and reprogram the NT timer to be the firing time of the first queue in the list
    04891
    04892
    04893     for (QNode = TimerQueues.Flink ; QNode != &TimerQueues ; QNode = QNode->Flink) {
    04894
    04895         Queue = CONTAINING_RECORD (QNode, RTLP_TIMER_QUEUE, List) ;
    04896
    04897         // If the delta time in the timer queue is 0 - then this queue
    04898         // has timers that are ready to fire. Walk the list and fire all timers with
    04899         // Delta time of 0
    04900
    04901         if (Queue->DeltaFiringTime == 0) {
    04902
    04903             // Walk all timers with DeltaFiringTime == 0 and fire them. After that
    04904             // reinsert the periodic timers in the appropriate place.
    04905
    04906             RtlpFireTimersAndReorder (Queue, &NewFiringTime, &TimersToFireList) ;
    04907
    04908             // detach this Queue from the list
    04909
    04910             QNode = QNode->Blink ;
    04911
    04912             RemoveEntryList (QNode->Flink) ;
    04913
    04914             // If there are timers in the queue then prepare to reinsert the queue in
    04915             // TimerQueues.
    04916
    04917             if (NewFiringTime != INFINITE_TIME) {
    04918
    04919                 Queue->DeltaFiringTime = NewFiringTime ;
    04920
    04921                 // put the timer in list that we will process after we have
    04922                 // fired all elements in this queue
    04923
    04924                 InsertHeadList (&ReinsertTimerQueueList, &Queue->List) ;
    04925
    04926             } else {
    04927
    04928                 // Queue has no more timers in it. Let the Queue float.
    04929
    04930                 InitializeListHead (&Queue->List) ;
    04931
    04932             }
    04933
    04934
    04935         } else {
    04936
    04937             // No more Queues with DeltaFiringTime == 0
    04938
    04939             break ;
    04940
    04941         }
    04942
    04943     }
    04944
    04945     // At this point we have fired all the ready timers. We have two lists that need to be
    04946     // merged - TimerQueues and ReinsertTimerQueueList. The following steps do this - at the
    04947     // end of this we will reprogram the NT Timer.
    04948
    04949     if (!IsListEmpty(&TimerQueues)) {
    04950
    04951         Queue = CONTAINING_RECORD (TimerQueues.Flink, RTLP_TIMER_QUEUE, List) ;
    04952
    04953         NewFiringTime = Queue->DeltaFiringTime ;
    04954
    04955         Queue->DeltaFiringTime = 0 ;
    04956
    04957         if (!IsListEmpty (&ReinsertTimerQueueList)) {
    04958
    04959             // TimerQueues and ReinsertTimerQueueList are both non-empty. Merge them.
    04960
    04961             RtlpInsertTimersIntoDeltaList (&ReinsertTimerQueueList, &TimerQueues,
    04962                                             NewFiringTime, &NewFiringTime) ;
    04963
    04964         }
    04965
    04966         // NewFiringTime contains the time the NT Timer should be programmed to.
    04967
    04968     } else {
    04969
    04970         if (!IsListEmpty (&ReinsertTimerQueueList)) {
    04971
    04972             // TimerQueues is empty. ReinsertTimerQueueList is not.
    04973
    04974             RtlpInsertTimersIntoDeltaList (&ReinsertTimerQueueList, &TimerQueues, 0,
    04975                                             &NewFiringTime) ;
    04976
    04977         } else {
    04978
    04979             NewFiringTime = INFINITE_TIME ;
    04980
    04981         }
    04982
    04983         // NewFiringTime contains the time the NT Timer should be programmed to.
    04984
    04985     }
    04986
    04987
    04988     // Reset the timer to reflect the Delta time associated with the first Queue
    04989
    04990     RtlpResetTimer (TimerHandle, NewFiringTime, NULL) ;
    04991
    04992     if (DPRN3) {
    04993         DbgPrint("After service timer:ThreadId<%x:%x>\n",
    04994                     HandleToUlong(NtCurrentTeb()->ClientId.UniqueThread),
    04995                     HandleToUlong(NtCurrentTeb()->ClientId.UniqueProcess));
    04996         RtlDebugPrintTimes ();
    04997     }
    04998
    04999
    05000     // finally fire all the timers
    05001
    05002     RtlpFireTimers( &TimersToFireList ) ;
    05003
    05004     RELEASE_GLOBAL_TIMER_LOCK();
    05005
    05006 }

NTSTATUS RtlpStartIOWorkerThread | ( |  | ) |

Definition at line 1820 of file threads.c.

References LastThreadCreationTickCount, NtClose(), NtGetTickCount(), NTSTATUS(), NumIOWorkerThreads, RtlpIOWorkerThread(), RtlpStartThreadFunc, Status, and ThreadHandle.

Referenced by RtlQueueWorkItem().

    01824                    :
    01825
    01826     This routine starts an I/O worker thread
    01827
    01828 Arguments:
    01829
    01830
    01831 Return Value:
    01832
    01833     NTSTATUS error codes resulting from attempts to create a thread
    01834     STATUS_SUCCESS
    01835
    01836 --*/
    01837 {
    01838     HANDLE ThreadHandle ;
    01839     ULONG CurrentTickCount ;
    01840     NTSTATUS Status ;
    01841
    01842
    01843     // Create worker thread
    01844
    01845     Status = RtlpStartThreadFunc (RtlpIOWorkerThread, &ThreadHandle) ;
    01846
    01847     if (Status == STATUS_SUCCESS ) {
    01848
    01849         NtClose( ThreadHandle ) ;
    01850
    01851         // Update the time at which the current thread was created
    01852
    01853         LastThreadCreationTickCount = NtGetTickCount() ;
    01854
    01855     } else {
    01856
    01857         // Thread creation failed. If there is even one thread present do not return
    01858         // failure since we can still service the work request.
    01859
    01860         if (NumIOWorkerThreads == 0) {
    01861
    01862             return Status ;
    01863
    01864         }
    01865     }
    01866
    01867     return STATUS_SUCCESS ;
    01868 }

NTSTATUS NTAPI RtlpStartThread | ( | PUSER_THREAD_START_ROUTINE | Function,
|  | HANDLE * | ThreadHandle
| ) |

Definition at line 2677 of file threads.c.

References FALSE, Initialized, L, NtDelayExecution(), NTSTATUS(), NULL, ONE_MILLISECOND_TIMEOUT, RtlCreateUserThread(), Status, and ThreadHandle.

    02683                    :
    02684
    02685     This routine is used start a new wait thread in the pool.
    02686 Arguments:
    02687
    02688     None
    02689
    02690 Return Value:
    02691
    02692     STATUS_SUCCESS - Timer Queue created successfully.
    02693
    02694     STATUS_NO_MEMORY - There was not sufficient heap to perform the requested operation.
    02695
    02696 --*/
    02697 {
    02698     NTSTATUS Status ;
    02699     ULONG Initialized ;
    02700     LARGE_INTEGER TimeOut ;
    02701
    02702     Initialized = FALSE ;
    02703
    02704     // Create the first thread. This thread never dies until the process exits
    02705
    02706     Status = RtlCreateUserThread(
    02707                    NtCurrentProcess(), // process handle
    02708                    NULL,               // security descriptor
    02709                    FALSE,              // Create suspended?
    02710                    0L,                 // ZeroBits: default
    02711                    0L,                 // Max stack size: default
    02712                    0L,                 // Committed stack size: default
    02713                    Function,           // Function to start in
    02714                    &Initialized,       // Event the thread signals when the thread is ready
    02715                    ThreadHandle,       // Thread handle
    02716                    NULL                // Thread id
    02717                    );
    02718
    02719     if ( Status == STATUS_SUCCESS ) {
    02720
    02721         // Sleep 1 ms and see if the other thread has completed initialization
    02722
    02723         ONE_MILLISECOND_TIMEOUT(TimeOut) ;
    02724
    02725         while (!(volatile ULONG) Initialized) {
    02726
    02727             NtDelayExecution (FALSE, &TimeOut) ;
    02728
    02729         }
    02730
    02731     }
    02732
    02733
    02734     return Status ;
    02735 }

NTSTATUS RtlpStartWorkerThread | ( |  | ) |

Definition at line 1763 of file threads.c.

References LastThreadCreationTickCount, NtClose(), NtGetTickCount(), NTSTATUS(), NumWorkerThreads, RtlpStartThreadFunc, RtlpWorkerThread(), Status, and ThreadHandle.

Referenced by RtlpWorkerThreadTimerCallback(), RtlQueueWorkItem(), and RtlSetIoCompletionCallback().

    01767                    :
    01768
    01769     This routine starts a regular worker thread
    01770
    01771 Arguments:
    01772
    01773
    01774 Return Value:
    01775
    01776     NTSTATUS error codes resulting from attempts to create a thread
    01777     STATUS_SUCCESS
    01778
    01779 --*/
    01780 {
    01781     HANDLE ThreadHandle ;
    01782     ULONG CurrentTickCount ;
    01783     NTSTATUS Status ;
    01784
    01785     // Create worker thread
    01786
    01787     Status = RtlpStartThreadFunc (RtlpWorkerThread, &ThreadHandle) ;
    01788
    01789     if (Status == STATUS_SUCCESS ) {
    01790
    01791         // Update the time at which the current thread was created
    01792
    01793         LastThreadCreationTickCount = NtGetTickCount() ;
    01794
    01795         // Increment the count of the thread type created
    01796
    01797         InterlockedIncrement(&NumWorkerThreads) ;
    01798
    01799         // Close Thread handle, we dont need it.
    01800
    01801         NtClose (ThreadHandle) ;
    01802
    01803     } else {
    01804
    01805         // Thread creation failed. If there is even one thread present do not return
    01806         // failure - else queue the request anyway.
    01807
    01808         if (NumWorkerThreads == 0) {
    01809
    01810             return Status ;
    01811         }
    01812
    01813     }
    01814
    01815     return STATUS_SUCCESS ;
    01816 }

VOID RtlpThreadCleanup | ( |  | ) |

Definition at line 5484 of file threads.c.

References NtTerminateThread().

Referenced by RtlThreadPoolCleanup().

    05488                    :
    05489
    05490     This routine is used for exiting timer, wait and IOworker threads.
    05491
    05492 Arguments:
    05493
    05494 Return Value:
    05495
    05496 --*/
    05497 {
    05498     NtTerminateThread( NtCurrentThread(), 0) ;
    05499 }

LONG RtlpTimerThread | ( | PVOID | Initialized | ) |

Definition at line 5201 of file threads.c.

References Initialized, NtDelayExecution(), NULL, RtlpResetTimer(), TimerHandle, TimerThreadId, and TRUE.

Referenced by RtlpInitializeTimerThreadPool().

    05206                    :
    05207
    05208     All the timer activity takes place in APCs.
    05209
    05210 Arguments:
    05211
    05212     Initialized - Used to notify the starter of the thread that thread initialization
    05213     has completed
    05214
    05215 Return Value:
    05216
    05217 --*/
    05218 {
    05219     LARGE_INTEGER TimeOut ;
    05220
    05221     // no structure initializations should be done here as new timer thread
    05222     // may be created after threadPoolCleanup
    05223
    05224
    05225     TimerThreadId = HandleToUlong(NtCurrentTeb()->ClientId.UniqueThread) ;
    05226
    05227
    05228     // Reset the NT Timer to never fire initially
    05229
    05230     RtlpResetTimer (TimerHandle, -1, NULL) ;
    05231
    05232     // Notify starter of this thread that it has initialized
    05233
    05234     InterlockedExchange ((ULONG *) Initialized, 1) ;
    05235
    05236     // Sleep alertably so that all the activity can take place
    05237     // in APCs
    05238
    05239     for ( ; ; ) {
    05240
    05241         // Set timeout for the largest timeout possible
    05242
    05243         TimeOut.LowPart = 0 ;
    05244         TimeOut.HighPart = 0x80000000 ;
    05245
    05246         NtDelayExecution (TRUE, &TimeOut) ;
    05247
    05248     }
    05249
    05250     return 0 ;  // Keep compiler happy
    05251
    05252 }

VOID RtlpUpdateTimer | ( | PRTLP_TIMER | Timer,
|  | PRTLP_TIMER | UpdatedTimer
| ) |

Definition at line 4044 of file threads.c.

References CHECK_SIGNATURE, NULL, PRTLP_TIMER_QUEUE, RtlpFreeTPHeap, RtlpGetQueueRelativeTime(), RtlpGetTimeRemaining(), RtlpReOrderDeltaList(), RtlpResetTimer(), RtlpResync64BitTickCount(), STATE_ACTIVE, TimerHandle, and TimerQueues.

Referenced by RtlUpdateTimer().

    04050                    :
    04051
    04052     This routine executes in an APC and updates the specified timer if it exists
    04053
    04054 Arguments:
    04055
    04056     Timer - Timer that is actually updated
    04057     UpdatedTimer - Specifies pointer to a timer structure that contains Queue and
    04058                 Timer information
    04059
    04060 Return Value:
    04061
    04062
    04063 --*/
    04064 {
    04065     PRTLP_TIMER_QUEUE Queue ;
    04066     ULONG TimeRemaining, QueueRelTimeRemaining ;
    04067     ULONG NewFiringTime ;
    04068
    04069
    04070     RtlpResync64BitTickCount( ) ;
    04071
    04072     CHECK_SIGNATURE(Timer) ;
    04073
    04074     Queue = Timer->Queue ;
    04075
    04076     // Update the periodic time on the timer
    04077
    04078     Timer->Period = UpdatedTimer->Period ;
    04079
    04080
    04081     // if timer is not in active state, then dont update it
    04082
    04083     if ( ! ( Timer->State & STATE_ACTIVE ) ) {
    04084
    04085         return ;
    04086     }
    04087
    04088     // Get the time remaining on the NT timer
    04089
    04090     TimeRemaining = RtlpGetTimeRemaining (TimerHandle) ;
    04091     QueueRelTimeRemaining = TimeRemaining + RtlpGetQueueRelativeTime (Queue) ;
    04092
    04093
    04094     // Update the timer based on the due time
    04095
    04096     if (RtlpReOrderDeltaList (&Queue->TimerList, Timer, QueueRelTimeRemaining,
    04097                                 &NewFiringTime,
    04098                                 UpdatedTimer->DeltaFiringTime))
    04099     {
    04100
    04101         // If this update caused the timer at the head of the queue to change, then reinsert
    04102         // this queue in the list of queues.
    04103
    04104         if (RtlpReOrderDeltaList (&TimerQueues, Queue, TimeRemaining, &NewFiringTime, NewFiringTime)) {
    04105
    04106             // NT timer needs to be updated since the change caused the queue at the head of
    04107             // the TimerQueues to change.
    04108
    04109             RtlpResetTimer (TimerHandle, NewFiringTime, NULL) ;
    04110
    04111         }
    04112
    04113     }
    04114
    04115     RtlpFreeTPHeap( UpdatedTimer ) ;
    04116 }

NTSTATUS RtlpWaitForEvent | ( | HANDLE | Event,
|  | HANDLE | ThreadHandle
| ) |

Definition at line 5503 of file threads.c.

References DbgPrint, Event(), FALSE, NT_SUCCESS, NtQueueApcThread(), NTSTATUS(), NtWaitForSingleObject(), NULL, ONE_SECOND_TIMEOUT, RtlpDoNothing(), Status, and ThreadHandle.

Referenced by RtlDeleteTimer(), RtlDeleteTimerQueueEx(), and RtlDeregisterWaitEx().

    05509                    :
    05510
    05511     Waits for the event to be signalled. If the event is not signalled within
    05512     one second, then checks to see that the thread is alive
    05513
    05514 Arguments:
    05515
    05516     Event : Event handle used for signalling completion of request
    05517
    05518     ThreadHandle: Thread to check whether still alive
    05519
    05520 Return Value:
    05521
    05522     STATUS_SUCCESS if event was signalled
    05523     else return NTSTATUS
    05524
    05525 --*/
    05526 {
    05527     NTSTATUS Status ;
    05528     LARGE_INTEGER TimeOut ;
    05529
    05530     // Timeout of 1 second for request to complete
    05531     ONE_SECOND_TIMEOUT(TimeOut) ;
    05532
    05533 Wait:
    05534
    05535     Status = NtWaitForSingleObject (Event, FALSE, &TimeOut) ;
    05536
    05537     if (Status == STATUS_TIMEOUT) {
    05538
    05539         // The wait timed out. Check to see if the wait thread is still alive.
    05540         // This is done by trying to queue a dummy APC to it. There is no better
    05541         // way known to determine if the thread has died unexpectedly.
    05542         // If so then go back to waiting.
    05543
    05544         Status = NtQueueApcThread(
    05545             ThreadHandle,
    05546             (PPS_APC_ROUTINE)RtlpDoNothing,
    05547             NULL,
    05548             NULL,
    05549             NULL
    05550             );
    05551
    05552         if (NT_SUCCESS(Status) ) {
    05553
    05554             // Wait thread is still alive. Go back to waiting.
    05555
    05556             goto Wait ;
    05557
    05558         } else {
    05559
    05560             // The wait thread died between the time the APC was queued and the
    05561             // the time we started waiting on NtQueryInformationThread()
    05562
    05563
    05564             DbgPrint ("Thread died before event could be signalled") ;
    05565
    05566         }
    05567
    05568     }
    05569
    05570     return NT_SUCCESS(Status) ? STATUS_SUCCESS : Status ;
    05571 }

LONG RtlpWaitThread | ( | PVOID | Initialized | ) |

Definition at line 2824 of file threads.c.

References ACQUIRE_GLOBAL_WAIT_LOCK, _RTLP_WAIT_THREAD_CONTROL_BLOCK::ActiveWaitArray, _RTLP_WAIT_THREAD_CONTROL_BLOCK::ActiveWaitPointers, ASSERT, CHAR, _RTLP_WAIT_THREAD_CONTROL_BLOCK::Current64BitTickCount, DbgPrint, EXCEPTION_EXECUTE_HANDLER, FALSE, _RTLP_WAIT_THREAD_CONTROL_BLOCK::Firing64BitTickCount, _RTLP_WAIT_THREAD_CONTROL_BLOCK::FreeTimerBlocks, Initialized, NT_SUCCESS, NtClose(), NtCreateTimer(), NtDelayExecution(), NtDuplicateObject(), NtGetTickCount(), NTSTATUS(), NtWaitForMultipleObjects(), NULL, _RTLP_WAIT_THREAD_CONTROL_BLOCK::NumActiveWaits, _RTLP_WAIT_THREAD_CONTROL_BLOCK::NumWaits, RELEASE_GLOBAL_WAIT_LOCK, RTLP_TIMER, RtlpExitThreadFunc, RtlpProcessTimeouts(), RtlpProcessWaitCompletion(), RtlpResetTimer(), Status, _RTLP_WAIT_THREAD_CONTROL_BLOCK::ThreadHandle, _RTLP_WAIT_THREAD_CONTROL_BLOCK::ThreadId, _RTLP_WAIT_THREAD_CONTROL_BLOCK::TimerBlocks, _RTLP_WAIT_THREAD_CONTROL_BLOCK::TimerHandle, _RTLP_WAIT_THREAD_CONTROL_BLOCK::TimerQueue, TRUE, WAIT_IDLE_TIMEOUT, WaitThreads, and _RTLP_WAIT_THREAD_CONTROL_BLOCK::WaitThreadsList.

Referenced by RtlpFindWaitThread().

    02829                    :
    02830
    02831     This routine is used for all waits in the wait thread pool
    02832
    02833 Arguments:
    02834
    02835     Initialized - This is set to 1 when the thread has initialized
    02836
    02837 Return Value:
    02838
    02839     Nothing. The thread never terminates.
    02840
    02841 --*/
    02842 {
    02843     ULONG  i ;                                   // Used as an index
    02844     NTSTATUS Status ;
    02845     LARGE_INTEGER TimeOut;                       // Timeout used for waits
    02846     PRTLP_WAIT_THREAD_CONTROL_BLOCK ThreadCB ;   // Control Block allocated on the stack
    02847 #define WAIT_IDLE_TIMEOUT 400000
    02848
    02849
    02850     try {
    02851         ThreadCB = (PRTLP_WAIT_THREAD_CONTROL_BLOCK)
    02852                         _alloca(sizeof(RTLP_WAIT_THREAD_CONTROL_BLOCK));
    02853
    02854     } except (EXCEPTION_EXECUTE_HANDLER) {
    02855
    02856         ASSERT(FALSE);
    02857         InterlockedExchange ((ULONG *)Initialized, (ULONG)~0) ;
    02858         return STATUS_NO_MEMORY;
    02859     }
    02860
    02861
    02862
    02863     // Initialize thread control block
    02864
    02865     InitializeListHead (&ThreadCB->WaitThreadsList) ;
    02866
    02867     Status = NtDuplicateObject(
    02868                 NtCurrentProcess(),
    02869                 NtCurrentThread(),
    02870                 NtCurrentProcess(),
    02871                 &ThreadCB->ThreadHandle,
    02872                 0,
    02873                 FALSE,
    02874                 DUPLICATE_SAME_ACCESS
    02875                 ) ;
    02876
    02877     if (!NT_SUCCESS(Status)) {
    02878         ASSERT (FALSE) ;
    02879         InterlockedExchange ((ULONG *)Initialized, (ULONG)~0) ;
    02880         return STATUS_NO_MEMORY;
    02881     }
    02882
    02883     ThreadCB->ThreadId =  HandleToUlong(NtCurrentTeb()->ClientId.UniqueThread) ;
    02884
    02885     RtlZeroMemory (&ThreadCB->ActiveWaitArray[0], sizeof (HANDLE) * 64) ;
    02886
    02887     RtlZeroMemory (&ThreadCB->ActiveWaitPointers[0], sizeof (HANDLE) * 64) ;
    02888
    02889
    02890
    02891     // Initialize the timer related fields.
    02892
    02893     Status = NtCreateTimer(
    02894                  &ThreadCB->TimerHandle,
    02895                  TIMER_ALL_ACCESS,
    02896                  NULL,
    02897                  NotificationTimer
    02898                  ) ;
    02899
    02900     if (! NT_SUCCESS( Status )) {
    02901         ASSERT (FALSE);
    02902         NtClose(ThreadCB->ThreadHandle) ;
    02903         InterlockedExchange ((ULONG *)Initialized, (ULONG)~0) ;
    02904         return STATUS_NO_MEMORY;
    02905     }
    02906
    02907
    02908     ThreadCB->Firing64BitTickCount = 0 ;
    02909     ThreadCB->Current64BitTickCount.QuadPart = NtGetTickCount() ;
    02910
    02911     // Reset the NT Timer to never fire initially
    02912
    02913     RtlpResetTimer (ThreadCB->TimerHandle, -1, ThreadCB) ;
    02914
    02915     InitializeListHead (&ThreadCB->TimerQueue.TimerList) ;
    02916     InitializeListHead (&ThreadCB->TimerQueue.UncancelledTimerList) ;
    02917
    02918
    02919     // Initialize the timer blocks
    02920
    02921     RtlZeroMemory (&ThreadCB->TimerBlocks[0], sizeof (RTLP_TIMER) * 63) ;
    02922
    02923     InitializeListHead (&ThreadCB->FreeTimerBlocks) ;
    02924
    02925     for (i = 0 ; i < 63 ; i++) {
    02926
    02927         InitializeListHead (&(&ThreadCB->TimerBlocks[i])->List) ;
    02928         InsertHeadList (&ThreadCB->FreeTimerBlocks, &(&ThreadCB->TimerBlocks[i])->List) ;
    02929
    02930     }
    02931
    02932
    02933     // Insert this new wait thread in the WaitThreads list. Insert at the head so that
    02934     // the request that caused this thread to be created can find it right away.
    02935
    02936     InsertHeadList (&WaitThreads, &ThreadCB->WaitThreadsList) ;
    02937
    02938
    02939     // The first wait element is the timer object
    02940
    02941     ThreadCB->ActiveWaitArray[0] = ThreadCB->TimerHandle ;
    02942
    02943     ThreadCB->NumActiveWaits = ThreadCB->NumWaits = 1 ;
    02944
    02945
    02946     // till here, the function is running under the global wait lock
    02947
    02948
    02949
    02950     // We are all initialized now. Notify the starter to queue the task.
    02951
    02952     InterlockedExchange ((ULONG *)Initialized, 1) ;
    02953
    02954
    02955     // Loop forever - wait threads never, never die.
    02956
    02957     for ( ; ; ) {
    02958
    02959         if (ThreadCB->NumActiveWaits == 1)
    02960             TimeOut.QuadPart = Int32x32To64( WAIT_IDLE_TIMEOUT, -10000 ) ;
    02961
    02962         Status = NtWaitForMultipleObjects (
    02963                      (CHAR) ThreadCB->NumActiveWaits,
    02964                      ThreadCB->ActiveWaitArray,
    02965                      WaitAny,
    02966                      TRUE,      // Wait Alertably
    02967                      ThreadCB->NumWaits!=1 ? NULL : &TimeOut       // Wait forever
    02968                      ) ;
    02969
    02970         if (Status == STATUS_ALERTED || Status == STATUS_USER_APC) {
    02971
    02972             continue ;
    02973
    02974         } else if (Status >= STATUS_WAIT_0 && Status <= STATUS_WAIT_63) {
    02975
    02976             if (Status == STATUS_WAIT_0) {
    02977
    02978                 RtlpProcessTimeouts (ThreadCB) ;
    02979
    02980             } else {
    02981
    02982                 // Wait completed call Callback function
    02983
    02984                 RtlpProcessWaitCompletion (
    02985                         ThreadCB->ActiveWaitPointers[Status], Status) ;
    02986
    02987             }
    02988
    02989         } else if (Status >= STATUS_ABANDONED_WAIT_0
    02990                     && Status <= STATUS_ABANDONED_WAIT_63) {
    02991
    02992             #if DBG
    02993             DbgPrint ("RTL ThreadPool Wait Thread: Abandoned wait: %d\n",
    02994                         Status - STATUS_ABANDONED_WAIT_0 ) ;
    02995             #endif
    02996
    02997
    02998             // Abandoned wait
    02999
    03000             ASSERT (FALSE) ;
    03001
    03002         } else if (Status == STATUS_TIMEOUT) {
    03003
    03004             //
    03005             // remove this thread from the wait list and terminate
    03006             //
    03007
    03008             {
    03009                 ULONG NumWaits;
    03010
    03011                 ACQUIRE_GLOBAL_WAIT_LOCK() ;
    03012
    03013                 NumWaits = ThreadCB->NumWaits;
    03014
    03015                 if (ThreadCB->NumWaits <= 1) {
    03016                     RemoveEntryList(&ThreadCB->WaitThreadsList) ;
    03017                     NtClose(ThreadCB->ThreadHandle) ;
    03018                     NtClose(ThreadCB->TimerHandle) ;
    03019                 }
    03020
    03021                 RELEASE_GLOBAL_WAIT_LOCK() ;
    03022
    03023                 if (NumWaits <= 1) {
    03024
    03025                     RtlpExitThreadFunc( 0 );
    03026                 }
    03027             }
    03028
    03029         } else {
    03030
    03031             // Some other error: fatal condition
    03032             ULONG i ;
    03033
    03034 //            ASSERTMSG( "Press 'i', and note the dbgprint\n", FALSE ) ;
    03035
    03036             #if DBG
    03037             DbgPrint ("RTL Thread Pool: Application closed an object handle "
    03038                         "that the wait thread was waiting on: Code:%x ThreadId:<%x:%x>\n",
    03039                         Status, HandleToUlong(NtCurrentTeb()->ClientId.UniqueThread),
    03040                         HandleToUlong(NtCurrentTeb()->ClientId.UniqueProcess)) ;
    03041
    03042             TimeOut.QuadPart = 0 ;
    03043
    03044             for (i=0;  i<ThreadCB->NumActiveWaits;  i++) {
    03045
    03046                 Status = NtWaitForMultipleObjects(
    03047                              (CHAR) 1,
    03048                              &ThreadCB->ActiveWaitArray[i],
    03049                              WaitAny,
    03050                              TRUE,      // Wait Alertably
    03051                              &TimeOut   // Dont 0
    03052                              ) ;
    03053
    03054                 if (Status == STATUS_INVALID_HANDLE) {
    03055                     DbgPrint("Bad Handle index:%d WaitEntry Ptr:%x\n",
    03056                                 i, ThreadCB->ActiveWaitPointers[i]) ;
    03057                 }
    03058             }
    03059
    03060             #endif
    03061
    03062             ASSERT( FALSE ) ;
    03063
    03064
    03065             // Set timeout for the largest timeout possible
    03066
    03067             TimeOut.LowPart = 0 ;
    03068             TimeOut.HighPart = 0x80000000 ;
    03069
    03070             NtDelayExecution (TRUE, &TimeOut) ;
    03071
    03072         }
    03073
    03074     } // forever
    03075
    03076     return 0 ; // Keep compiler happy
    03077
    03078 }

LONG RtlpWorkerThread | ( | PVOID | Initialized | ) |

Definition at line 2137 of file threads.c.

References ASSERT, EXCEPTION_EXECUTE_HANDLER, FALSE, Initialized, L, MAX_WORKER_SLEEP_TIME_EXPONENT, NEW_THREAD_THRESHOLD, NT_SUCCESS, NtClose(), NtDuplicateObject(), NtQueryInformationThread(), NtRemoveIoCompletion(), NTSTATUS(), NULL, NumExecutingWorkerThreads, NumLongWorkRequests, NumMinWorkerThreads, NumWorkerThreads, NumWorkRequests, RtlpExitThreadFunc, Status, TotalExecutedWorkRequests, TRUE, WORKER_IDLE_TIMEOUT, WorkerCompletionPort, and WorkerCriticalSection.

Referenced by RtlpStartWorkerThread().

    02142                    :
    02143
    02144     All non I/O worker threads execute in this routine. Worker thread will try to
    02145     terminate when it has not serviced a request for
    02146
    02147         STARTING_WORKER_SLEEP_TIME +
    02148         STARTING_WORKER_SLEEP_TIME << 1 +
    02149         ...
    02150         STARTING_WORKER_SLEEP_TIME << MAX_WORKER_SLEEP_TIME_EXPONENT
    02151
    02152 Arguments:
    02153
    02154     Initialized - Set to 1 when we are initialized
    02155
    02156 Return Value:
    02157
    02158 --*/
    02159 {
    02160     NTSTATUS Status ;
    02161     PVOID WorkerProc ;
    02162     PVOID Context ;
    02163     IO_STATUS_BLOCK IoSb ;
    02164     ULONG SleepTime ;
    02165     LARGE_INTEGER TimeOut ;
    02166     ULONG Terminate ;
    02167     PVOID Overlapped ;
    02168
    02169
    02170     // We are all initialized now. Notify the starter to queue the task.
    02171
    02172     InterlockedExchange ((ULONG *)Initialized, 1L) ;
    02173
    02174
    02175     // Set default sleep time for 40 seconds. This time is doubled each time a timeout
    02176     // occurs after which the thread terminates
    02177
    02178 #define WORKER_IDLE_TIMEOUT     40000    // In Milliseconds
    02179 #define MAX_WORKER_SLEEP_TIME_EXPONENT 4
    02180
    02181     SleepTime = WORKER_IDLE_TIMEOUT ;
    02182
    02183     // Loop servicing I/O completion requests
    02184
    02185     for ( ; ; ) {
    02186
    02187         TimeOut.QuadPart = Int32x32To64( SleepTime, -10000 ) ;
    02188
    02189         Status = NtRemoveIoCompletion(
    02190                     WorkerCompletionPort,
    02191                     (PVOID) &WorkerProc,
    02192                     &Overlapped,
    02193                     &IoSb,
    02194                     &TimeOut
    02195                     ) ;
    02196
    02197         if (Status == STATUS_SUCCESS) {
    02198
    02199
    02200             TotalExecutedWorkRequests ++ ;//interlocked op not req
    02201             InterlockedIncrement(&NumExecutingWorkerThreads) ;
    02202
    02203             // Call the work item.
    02204             // If IO APC, context1 contains number of IO bytes transferred, and context2
    02205             // contains the overlapped structure.
    02206             // If (IO)WorkerFunction, context1 contains the actual WorkerFunction to be
    02207             // executed and context2 contains the actual context
    02208
    02209             Context = (PVOID) IoSb.Information ;
    02210
    02211             try {
    02212                 ((APC_CALLBACK_FUNCTION)WorkerProc) (
    02213                                             IoSb.Status,
    02214                                             Context,        // Number of IO bytes transferred
    02215                                             Overlapped      // Overlapped structure
    02216                                             ) ;
    02217             } except (EXCEPTION_EXECUTE_HANDLER) {
    02218                 ASSERT(FALSE);
    02219             }
    02220
    02221             SleepTime = WORKER_IDLE_TIMEOUT ;
    02222
    02223             InterlockedDecrement(&NumExecutingWorkerThreads) ;
    02224
    02225         } else if (Status == STATUS_TIMEOUT) {
    02226
    02227             // NtRemoveIoCompletion timed out. Check to see if have hit our limit
    02228             // on waiting. If so terminate.
    02229
    02230             Terminate = FALSE ;
    02231
    02232             RtlEnterCriticalSection (&WorkerCriticalSection) ;
    02233
    02234             // The thread terminates if there are > 1 threads and the queue is small
    02235             // OR if there is only 1 thread and there is no request pending
    02236
    02237             if (NumWorkerThreads >  1) {
    02238
    02239                 ULONG NumEffWorkerThreads = (NumWorkerThreads - NumLongWorkRequests) ;
    02240
    02241                 if (NumEffWorkerThreads == 0) {
    02242
    02243                     Terminate = FALSE ;
    02244
    02245                 } else if (SleepTime >= (WORKER_IDLE_TIMEOUT << MAX_WORKER_SLEEP_TIME_EXPONENT)) {
    02246
    02247                     //
    02248                     // have been idle for very long time. terminate irrespective of number of
    02249                     // work items. (This is useful when the set of runnable threads is taking
    02250                     // care of all the work items being queued). dont terminate if
    02251                     // (NumEffWorkerThreads == 1)
    02252                     //
    02253
    02254                     if (NumEffWorkerThreads > 1)
    02255                         Terminate = TRUE ;
    02256
    02257                 } else {
    02258
    02259                     ULONG Threshold ;
    02260
    02261                     // Check if we need to shrink worker thread pool
    02262
    02263                     Threshold = NumEffWorkerThreads < 7
    02264                                 ? NumEffWorkerThreads*(NumEffWorkerThreads-1)
    02265                                 : NEW_THREAD_THRESHOLD * (NumEffWorkerThreads-1);
    02266
    02267
    02268
    02269                     if  (NumWorkRequests-NumLongWorkRequests < Threshold)  {
    02270
    02271                         Terminate = TRUE ;
    02272
    02273                     } else {
    02274
    02275                         Terminate = FALSE ;
    02276                         SleepTime <<= 1 ;
    02277                     }
    02278                 }
    02279
    02280             } else {
    02281
    02282                 if ( (NumMinWorkerThreads == 0) && (NumWorkRequests == 0) ) {
    02283
    02284                     // delay termination of last thread
    02285
    02286                     if (SleepTime < (WORKER_IDLE_TIMEOUT << MAX_WORKER_SLEEP_TIME_EXPONENT)) {
    02287                         SleepTime <<= 1 ;
    02288                         Terminate = FALSE ;
    02289                     }
    02290                     else {
    02291                         Terminate = TRUE ;
    02292                     }
    02293
    02294                 } else {
    02295
    02296                     Terminate = FALSE ;
    02297
    02298                 }
    02299
    02300             }
    02301
    02302             if (Terminate) {
    02303
    02304                 THREAD_BASIC_INFORMATION ThreadInfo;
    02305                 ULONG IsIoPending ;
    02306                 HANDLE CurThreadHandle ;
    02307
    02308                 Status = NtDuplicateObject(
    02309                             NtCurrentProcess(),
    02310                             NtCurrentThread(),
    02311                             NtCurrentProcess(),
    02312                             &CurThreadHandle,
    02313                             0,
    02314                             FALSE,
    02315                             DUPLICATE_SAME_ACCESS
    02316                             ) ;
    02317
    02318                 ASSERT (Status == STATUS_SUCCESS) ;
    02319
    02320                 Terminate = FALSE ;
    02321
    02322                 Status = NtQueryInformationThread( CurThreadHandle,
    02323                                                    ThreadIsIoPending,
    02324                                                    &IsIoPending,
    02325                                                    sizeof( IsIoPending ),
    02326                                                    NULL
    02327                                                  );
    02328                 if (NT_SUCCESS( Status )) {
    02329
    02330                     if (! IsIoPending )
    02331                         Terminate = TRUE ;
    02332                 }
    02333
    02334                 NtClose( CurThreadHandle ) ;
    02335             }
    02336
    02337             if (Terminate) {
    02338
    02339                 InterlockedDecrement (&NumWorkerThreads) ;
    02340
    02341                 RtlLeaveCriticalSection (&WorkerCriticalSection) ;
    02342
    02343                 RtlpExitThreadFunc( 0 );
    02344
    02345             } else {
    02346
    02347                 // This is the condition where a request was queued *after* the
    02348                 // thread woke up - ready to terminate because of inactivity. In
    02349                 // this case dont terminate - service the completion port.
    02350
    02351                 RtlLeaveCriticalSection (&WorkerCriticalSection) ;
    02352
    02353             }
    02354
    02355         } else {
    02356
    02357             ASSERT (FALSE) ;
    02358
    02359         }
    02360
    02361     }
    02362
    02363
    02364     return 1 ;
    02365 }

VOID RtlpWorkerThreadInitializeTimers | ( | PVOID | Context | ) |

Definition at line 2104 of file threads.c.

References NT_SUCCESS, NTSTATUS(), NULL, RtlCreateTimer(), RtlCreateTimerQueue(), RtlpWorkerThreadTimerCallback(), Status, WorkerThreadTimer, and WorkerThreadTimerQueue.

Referenced by RtlpInitializeWorkerThreadPool().

    02107 {
    02108     NTSTATUS Status;
    02109
    02110
    02111     // create a timer that will fire every 30 sec and check if new thread
    02112     // should be created
    02113
    02114     Status = RtlCreateTimerQueue(&WorkerThreadTimerQueue) ;
    02115     if (!NT_SUCCESS(Status))
    02116         return ;
    02117
    02118     Status = RtlCreateTimer(
    02119                         WorkerThreadTimerQueue,
    02120                         &WorkerThreadTimer,
    02121                         RtlpWorkerThreadTimerCallback,
    02122                         NULL,
    02123                         30000,
    02124                         30000,
    02125                         WT_EXECUTEINTIMERTHREAD
    02126                         ) ;
    02127
    02128    return;
    02129 }

VOID RtlpWorkerThreadTimerCallback | ( | PVOID | Context,
|  | BOOLEAN | NotUsed
| ) |

Definition at line 1872 of file threads.c.

References FALSE, MAX_WORKER_THREADS, NEW_THREAD_THRESHOLD, NT_SUCCESS, NtQueryIoCompletion(), NTSTATUS(), NULL, NumExecutingWorkerThreads, NumLongWorkRequests, NumWorkerThreads, OldTotalExecutedWorkRequests, RtlpStartWorkerThread(), Status, TotalExecutedWorkRequests, TRUE, WorkerCompletionPort, and WorkerCriticalSection.

Referenced by RtlpWorkerThreadInitializeTimers().

    01878                    :
    01879
    01880     This routine checks if new worker thread has to be created
    01881
    01882 Arguments:
    01883     None
    01884
    01885 Return Value:
    01886     None
    01887
    01888 --*/
    01889 {
    01890     IO_COMPLETION_BASIC_INFORMATION Info ;
    01891     BOOLEAN bCreateThread = FALSE ;
    01892     NTSTATUS Status ;
    01893     ULONG QueueLength, Threshold, ShortWorkRequests ;
    01894
    01895
    01896     Status = NtQueryIoCompletion(
    01897                 WorkerCompletionPort,
    01898                 IoCompletionBasicInformation,
    01899                 &Info,
    01900                 sizeof(Info),
    01901                 NULL
    01902                 ) ;
    01903
    01904     if (!NT_SUCCESS(Status))
    01905         return ;
    01906
    01907     QueueLength = Info.Depth ;
    01908
    01909     if (!QueueLength) {
    01910         OldTotalExecutedWorkRequests = TotalExecutedWorkRequests ;
    01911         return ;
    01912     }
    01913
    01914
    01915     RtlEnterCriticalSection (&WorkerCriticalSection) ;
    01916
    01917
    01918     // if there are queued work items and no new work items have been scheduled
    01919     // in the last 30 seconds then create a new thread.
    01920     // this will take care of deadlocks.
    01921
    01922     // this will create a problem only if some thread is running for a long time
    01923
    01924     if (TotalExecutedWorkRequests == OldTotalExecutedWorkRequests) {
    01925
    01926         bCreateThread = TRUE ;
    01927     }
    01928
    01929
    01930     // if there are a lot of queued work items, then create a new thread
    01931     {
    01932         ULONG NumEffWorkerThreads = (NumWorkerThreads - NumLongWorkRequests) ;
    01933         ULONG ShortWorkRequests ;
    01934
    01935         Threshold = (NumWorkerThreads < MAX_WORKER_THREADS
    01936                         ? (NumEffWorkerThreads < 7
    01937                             ? NumEffWorkerThreads*NumEffWorkerThreads
    01938                             : NEW_THREAD_THRESHOLD * NumEffWorkerThreads )
    01939                         : 0xffffffff) ;
    01940
    01941         ShortWorkRequests = QueueLength + NumExecutingWorkerThreads
    01942                                 - NumLongWorkRequests ;
    01943
    01944         if (ShortWorkRequests  > Threshold)
    01945         {
    01946             bCreateThread = TRUE ;
    01947         }
    01948     }
    01949
    01950     if (bCreateThread) {
    01951
    01952         RtlpStartWorkerThread () ;
    01953     }
    01954
    01955
    01956     OldTotalExecutedWorkRequests = TotalExecutedWorkRequests ;
    01957
    01958     RtlLeaveCriticalSection (&WorkerCriticalSection) ;
    01959
    01960 }

NTSTATUS RtlQueueWorkItem | ( | IN WORKERCALLBACKFUNC | Function,
|  | IN PVOID | Context,
|  | IN ULONG | Flags
| ) |

Definition at line 437 of file threads.c.

References CompletedWorkerInitialization, LastThreadCreationTickCount, MAX_WORKER_THREADS, NEW_THREAD_THRESHOLD, NT_SUCCESS, NtGetTickCount(), NTSTATUS(), NumIOWorkerThreads, NumIOWorkRequests, NumLongIOWorkRequests, NumLongWorkRequests, NumMinWorkerThreads, NumWorkerThreads, NumWorkRequests, PersistentIOTCB, RtlpInitializeWorkerThreadPool(), RtlpQueueIOWorkerRequest(), RtlpQueueWorkerRequest(), RtlpStartIOWorkerThread(), RtlpStartWorkerThread(), Status, THREAD_CREATION_DAMPING_TIME1, THREAD_CREATION_DAMPING_TIME2, and WorkerCriticalSection.

Referenced by RtlpFireTimers(), RtlpInitializeWorkerThreadPool(), RtlpLpcServerCallback(), and RtlpProcessWaitCompletion().

    00445                    :
    00446
    00447     This routine queues up the request to be executed in a worker thread.
    00448
    00449 Arguments:
    00450
    00451     Function - Routine that is called by the worker thread
    00452
    00453     Context - Opaque pointer passed in as an argument to WorkerProc
    00454
    00455     Flags - Can be:
    00456
    00457             WT_EXECUTEINIOTHREAD - Specifies that the WorkerProc should be invoked
    00458             by a thread that is never destroyed when there are pending IO requests.
    00459             This can be used by threads that invoke I/O and/or schedule APCs.
    00460
    00461             The below flag can also be set:
    00462             WT_EXECUTELONGFUNCTION - Specifies that the function might block for a
    00463             long duration.
    00464
    00465 Return Value:
    00466
    00467     STATUS_SUCCESS - Queued successfully.
    00468
    00469     STATUS_NO_MEMORY - There was not sufficient heap to perform the
    00470         requested operation.
    00471
    00472 --*/
    00473
    00474 {
    00475     ULONG Threshold ;
    00476     ULONG CurrentTickCount ;
    00477     NTSTATUS Status = STATUS_SUCCESS ;
    00478
    00479
    00480     // Make sure the worker thread pool is initialized
    00481
    00482     if (CompletedWorkerInitialization != 1) {
    00483
    00484         Status = RtlpInitializeWorkerThreadPool () ;
    00485
    00486         if (! NT_SUCCESS(Status) )
    00487             return Status ;
    00488     }
    00489
    00490
    00491     // Take lock for the global worker thread pool
    00492
    00493     RtlEnterCriticalSection (&WorkerCriticalSection) ;
    00494
    00495
    00496     if (Flags & (WT_EXECUTEINIOTHREAD |WT_EXECUTEINUITHREAD |WT_EXECUTEINPERSISTENTIOTHREAD) ){
    00497
    00498         //
    00499         // execute in IO Worker thread
    00500         //
    00501
    00502         ULONG NumEffIOWorkerThreads = NumIOWorkerThreads - NumLongIOWorkRequests ;
    00503         ULONG ThreadCreationDampingTime = NumIOWorkerThreads < NEW_THREAD_THRESHOLD
    00504                                             ? THREAD_CREATION_DAMPING_TIME1
    00505                                             : THREAD_CREATION_DAMPING_TIME2 ;
    00506
    00507         if (PersistentIOTCB && (Flags&WT_EXECUTELONGFUNCTION))
    00508             NumEffIOWorkerThreads -- ;
    00509
    00510
    00511         // Check if we need to grow I/O worker thread pool
    00512
    00513         Threshold = (NumEffIOWorkerThreads < MAX_WORKER_THREADS
    00514                     ? NEW_THREAD_THRESHOLD * NumEffIOWorkerThreads
    00515                     : 0xffffffff) ;
    00516
    00517         if (LastThreadCreationTickCount > NtGetTickCount())
    00518             LastThreadCreationTickCount = NtGetTickCount() ;
    00519
    00520         if (NumEffIOWorkerThreads == 0
    00521             || ((NumIOWorkRequests - NumLongIOWorkRequests > Threshold)
    00522                     && (LastThreadCreationTickCount + ThreadCreationDampingTime
    00523                         < NtGetTickCount()))) {
    00524
    00525             // Grow the IO worker thread pool
    00526
    00527             Status = RtlpStartIOWorkerThread () ;
    00528
    00529         }
    00530
    00531         if (Status == STATUS_SUCCESS) {
    00532
    00533             // Queue the work request
    00534
    00535             Status = RtlpQueueIOWorkerRequest (Function, Context, Flags) ;
    00536         }
    00537
    00538
    00539     } else {
    00540
    00541         //
    00542         // execute in regular worker thread
    00543         //
    00544
    00545         ULONG NumEffWorkerThreads = (NumWorkerThreads - NumLongWorkRequests) ;
    00546         ULONG ThreadCreationDampingTime = NumWorkerThreads < NEW_THREAD_THRESHOLD
    00547                                             ? THREAD_CREATION_DAMPING_TIME1
    00548                                             : (NumWorkerThreads < 50
    00549                                                 ? THREAD_CREATION_DAMPING_TIME2
    00550                                                 : NumWorkerThreads << 7); // *100ms
    00551
    00552         // if io completion set, then have 1 more thread
    00553
    00554         if (NumMinWorkerThreads && NumEffWorkerThreads)
    00555             NumEffWorkerThreads -- ;
    00556
    00557
    00558         // Check if we need to grow worker thread pool
    00559
    00560         Threshold = (NumWorkerThreads < MAX_WORKER_THREADS
    00561                     ? (NumEffWorkerThreads < 7
    00562                         ? NumEffWorkerThreads*NumEffWorkerThreads
    00563                         : NEW_THREAD_THRESHOLD * NumEffWorkerThreads )
    00564                     : 0xffffffff) ;
    00565
    00566         if (LastThreadCreationTickCount > NtGetTickCount())
    00567             LastThreadCreationTickCount = NtGetTickCount() ;
    00568
    00569         if (NumEffWorkerThreads == 0 ||
    00570             ( (NumWorkRequests - NumLongWorkRequests >= Threshold)
    00571                     && (LastThreadCreationTickCount + ThreadCreationDampingTime
    00572                             < NtGetTickCount())))
    00573         {
    00574
    00575             // Grow the worker thread pool
    00576
    00577             Status = RtlpStartWorkerThread () ;
    00578
    00579         }
    00580
    00581         // Queue the work request
    00582
    00583         if (Status == STATUS_SUCCESS) {
    00584
    00585             Status = RtlpQueueWorkerRequest (Function, Context, Flags) ;
    00586         }
    00587
    00588     }
    00589
    00590     // Release lock on the worker thread pool
    00591
    00592     RtlLeaveCriticalSection (&WorkerCriticalSection) ;
    00593
    00594     return Status ;
    00595 }

NTSTATUS RtlRegisterWait | ( | OUT PHANDLE | WaitHandle,
|  | IN HANDLE | Handle,
|  | IN WAITORTIMERCALLBACKFUNC | Function,
|  | IN PVOID | Context,
|  | IN ULONG | Milliseconds,
|  | IN ULONG | Flags
| ) |

Definition at line 77 of file threads.c.

References CompletedWaitInitialization, _RTLP_WAIT::Context, _RTLP_WAIT::DbgId, DbgPrint, DPRN0, Event(), _RTLP_WAIT::Flags, _RTLP_WAIT::Function, Handle, NextWaitDbgId, NT_SUCCESS, NtQueueApcThread(), NTSTATUS(), NULL, PRTLP_EVENT, PRTLP_WAIT, PRTLP_WAIT_THREAD_CONTROL_BLOCK, RTLP_WAIT, RtlpAddWait(), RtlpAllocateTPHeap, RtlpFindWaitThread(), RtlpFreeTPHeap, RtlpInitializeWaitThreadPool(), SET_SIGNATURE, Status, _RTLP_WAIT::ThreadCB, _RTLP_WAIT_THREAD_CONTROL_BLOCK::ThreadHandle, _RTLP_WAIT::ThreadId, _RTLP_WAIT::Timeout, and _RTLP_WAIT::WaitHandle.

Referenced by RtlCreateLpcServer(), and RtlpLpcServerCallback().

    00088                    :
    00089
    00090     This routine adds a new wait request to the pool of objects being waited on.
    00091
    00092 Arguments:
    00093
    00094     WaitHandle - Handle returned on successful completion of this routine.
    00095
    00096     Handle - Handle to the object to be waited on
    00097
    00098     Function - Routine that is called when the wait completes or a timeout occurs
    00099
    00100     Context - Opaque pointer passed in as an argument to Function
    00101
    00102     Milliseconds - Timeout for the wait in milliseconds. 0xffffffff means dont
    00103             timeout.
    00104
    00105     Flags - Can be one of:
    00106
    00107         WT_EXECUTEINWAITTHREAD - if WorkerProc should be invoked in the wait
    00108                 thread itself. This should only be used for small routines.
    00109         WT_EXECUTEINIOTHREAD - use only if the WorkerProc should be invoked in
    00110                 an IO Worker thread. Avoid using it.
    00111
    00112     If Flags is not WT_EXECUTEINWAITTHREAD, the following flag can also be set:
    00113
    00114         WT_EXECUTELONGFUNCTION - indicates that the callback might be blocked
    00115                 for a long duration. Use only if the callback is being queued to a
    00116                 worker thread.
    00117
    00118 Return Value:
    00119
    00120     NTSTATUS - Result code from call.  The following are returned
    00121
    00122     STATUS_SUCCESS - The registration was successful.
    00123
    00124     STATUS_NO_MEMORY - There was not sufficient heap to perform the requested
    00125                 operation.
    00126
    00127     or other NTSTATUS error code
    00128
    00129 --*/
    00130
    00131 {
    00132     PRTLP_WAIT Wait ;
    00133     NTSTATUS Status ;
    00134     PRTLP_EVENT Event ;
    00135     LARGE_INTEGER TimeOut ;
    00136     PRTLP_WAIT_THREAD_CONTROL_BLOCK ThreadCB = NULL;
    00137
    00138     *WaitHandle = NULL ;
    00139
    00140
    00141     // Initialize thread pool if it isnt already done
    00142
    00143     if ( CompletedWaitInitialization != 1) {
    00144
    00145         Status = RtlpInitializeWaitThreadPool () ;
    00146
    00147         if (! NT_SUCCESS( Status ) )
    00148             return Status ;
    00149     }
    00150
    00151
    00152     // Initialize Wait request
    00153
    00154     Wait = (PRTLP_WAIT) RtlpAllocateTPHeap ( sizeof (RTLP_WAIT),
    00155                                             HEAP_ZERO_MEMORY) ;
    00156
    00157     if (!Wait) {
    00158         return STATUS_NO_MEMORY ;
    00159     }
    00160
    00161     Wait->WaitHandle = Handle ;
    00162     Wait->Flags = Flags ;
    00163     Wait->Function = Function ;
    00164     Wait->Context = Context ;
    00165     Wait->Timeout = Milliseconds ;
    00166     SET_SIGNATURE(Wait) ;
    00167
    00168
    00169     // timer part of wait is initialized by wait thread in RtlpAddWait
    00170
    00171
    00172     // Get a wait thread that can accomodate another wait request.
    00173
    00174     Status = RtlpFindWaitThread (&ThreadCB) ;
    00175
    00176     if (Status != STATUS_SUCCESS) {
    00177
    00178         RtlpFreeTPHeap( Wait ) ;
    00179
    00180         return Status ;
    00181     }
    00182
    00183     Wait->ThreadCB = ThreadCB ;
    00184
    00185     #if DBG1
    00186     Wait->DbgId = ++NextWaitDbgId ;
    00187     Wait->ThreadId = HandleToUlong(NtCurrentTeb()->ClientId.UniqueThread) ;
    00188     if (DPRN0)
    00189     DbgPrint("<%d:%d> Wait %x created by thread:<%x:%x>\n\n",
    00190                 Wait->DbgId, 1, (ULONG_PTR)Wait,
    00191                 HandleToUlong(NtCurrentTeb()->ClientId.UniqueThread),
    00192                 HandleToUlong(NtCurrentTeb()->ClientId.UniqueProcess)) ;
    00193     #endif
    00194
    00195     // Set the wait handle
    00196
    00197     *WaitHandle = Wait ;
    00198
    00199
    00200     // Queue an APC to the Wait Thread
    00201
    00202     Status = NtQueueApcThread(
    00203                     ThreadCB->ThreadHandle,
    00204                     (PPS_APC_ROUTINE)RtlpAddWait,
    00205                     (PVOID)Wait,
    00206                     NULL,
    00207                     NULL
    00208                     );
    00209
    00210
    00211     if ( NT_SUCCESS(Status) ) {
    00212
    00213         Status = STATUS_SUCCESS ;
    00214
    00215     } else {
    00216
    00217         *WaitHandle = NULL ;
    00218         RtlpFreeTPHeap( Wait ) ;
    00219     }
    00220
    00221     return Status ;
    00222
    00223 }

NTSTATUS RtlSetIoCompletionCallback | ( | IN HANDLE | FileHandle,
|  | IN APC_CALLBACK_FUNCTION | CompletionProc,
|  | IN ULONG | Flags
| ) |

Definition at line 600 of file threads.c.

References CompletedWorkerInitialization, NT_SUCCESS, NtSetInformationFile(), NTSTATUS(), NumMinWorkerThreads, NumWorkerThreads, RtlpInitializeWorkerThreadPool(), RtlpStartWorkerThread(), Status, WorkerCompletionPort, and WorkerCriticalSection.

    00608                    :
    00609
    00610     This routine binds an Handle and an associated callback function to the
    00611     IoCompletionPort which queues work items to worker threads.
    00612
    00613 Arguments:
    00614
    00615     Handle - handle to be bound to the IO completion port
    00616
    00617     CompletionProc - callback function to be executed when an IO request
    00618         pending on the IO handle completes.
    00619
    00620     Flags - Reserved. pass 0.
    00621
    00622 --*/
    00623
    00624 {
    00625     IO_STATUS_BLOCK IoSb ;
    00626     FILE_COMPLETION_INFORMATION CompletionInfo ;
    00627     NTSTATUS Status;
    00628
    00629
    00630     // Make sure that the worker thread pool is initialized as the file handle
    00631     // is bound to IO completion port.
    00632
    00633     if (CompletedWorkerInitialization != 1) {
    00634
    00635         Status = RtlpInitializeWorkerThreadPool () ;
    00636
    00637         if (! NT_SUCCESS(Status) )
    00638             return Status ;
    00639
    00640     }
    00641
    00642
    00643     //
    00644     // from now on NumMinWorkerThreads should be 1. If there is only 1 worker thread
    00645     // create a new one.
    00646     //
    00647
    00648     if ( NumMinWorkerThreads == 0 ) {
    00649
    00650         // Take lock for the global worker thread pool
    00651
    00652         RtlEnterCriticalSection (&WorkerCriticalSection) ;
    00653
    00654         if (NumWorkerThreads == 0) {
    00655
    00656             Status = RtlpStartWorkerThread () ;
    00657
    00658             if ( ! NT_SUCCESS(Status) ) {
    00659
    00660                 RtlLeaveCriticalSection (&WorkerCriticalSection) ;
    00661                 return Status ;
    00662             }
    00663         }
    00664
    00665         // from now on, there will be at least 1 worker thread
    00666         NumMinWorkerThreads = 1 ;
    00667
    00668         RtlLeaveCriticalSection (&WorkerCriticalSection) ;
    00669
    00670     }
    00671
    00672
    00673     // bind to IoCompletionPort, which queues work items to worker threads
    00674
    00675     CompletionInfo.Port = WorkerCompletionPort ;
    00676     CompletionInfo.Key = (PVOID) CompletionProc ;
    00677
    00678     Status = NtSetInformationFile (
    00679                         FileHandle,
    00680                         &IoSb, //not initialized
    00681                         &CompletionInfo,
    00682                         sizeof(CompletionInfo),
    00683                         FileCompletionInformation //enum flag
    00684                         ) ;
    00685     return Status ;
    00686 }

NTSTATUS NTAPI RtlSetThreadPoolStartFunc | ( | PRTLP_START_THREAD | StartFunc,
|  | PRTLP_EXIT_THREAD | ExitFunc
| ) |

Definition at line 1291 of file threads.c.

References RtlpExitThreadFunc, and RtlpStartThreadFunc.

    01297                    :
    01298
    01299     This routine sets the thread pool's thread creation function.  This is not
    01300     thread safe, because it is intended solely for kernel32 to call for processes
    01301     that aren't csrss/smss.
    01302
    01303 Arguments:
    01304
    01305     StartFunc - Function to create a new thread
    01306
    01307 Return Value:
    01308
    01309 --*/
    01310
    01311 {
    01312     RtlpStartThreadFunc = StartFunc ;
    01313     RtlpExitThreadFunc = ExitFunc ;
    01314     return STATUS_SUCCESS ;
    01315 }

NTSTATUS RtlSetTimer | ( | IN HANDLE | TimerQueueHandle,
|  | OUT HANDLE * | Handle,
|  | IN WAITORTIMERCALLBACKFUNC | Function,
|  | IN PVOID | Context,
|  | IN ULONG | DueTime,
|  | IN ULONG | Period,
|  | IN ULONG | Flags
| ) |

Definition at line 5818 of file threads.c.

References Count, DbgPrint, Handle, and RtlCreateTimer().

    05827 {
    05828     static ULONG Count = 0;
    05829     if (Count++ ==0) {
    05830         DbgPrint("Using obsolete function call: RtlSetTimer\n");
    05831         DbgBreakPoint();
    05832         DbgPrint("Using obsolete function call: RtlSetTimer\n");
    05833     }
    05834
    05835     return RtlCreateTimer(TimerQueueHandle,
    05836                             Handle,
    05837                             Function,
    05838                             Context,
    05839                             DueTime,
    05840                             Period,
    05841                             Flags
    05842                             ) ;
    05843 }

NTSTATUS RtlThreadPoolCleanup | ( | ULONG | Flags | ) |

Definition at line 1320 of file threads.c.

References ACQUIRE_GLOBAL_TIMER_LOCK, ACQUIRE_GLOBAL_WAIT_LOCK, ASSERTMSG, CompletedTimerInitialization, CompletedWaitInitialization, CompletedWorkerInitialization, FALSE, IOWorkerThreads, IS_COMPONENT_INITIALIZED, List, _RTLP_IOWORKER_TCB::List, NtClose(), NtQueueApcThread(), NtSetIoCompletion(), NULL, NumIOWorkerThreads, NumIOWorkRequests, NumTimerQueues, _RTLP_WAIT_THREAD_CONTROL_BLOCK::NumWaits, NumWorkerThreads, NumWorkRequests, RELEASE_GLOBAL_TIMER_LOCK, RELEASE_GLOBAL_WAIT_LOCK, RTLP_IOWORKER_TCB, RTLP_WAIT_THREAD_CONTROL_BLOCK, RtlpThreadCleanup(), StartedTimerInitialization, StartedWaitInitialization, StartedWorkerInitialization, _RTLP_WAIT_THREAD_CONTROL_BLOCK::ThreadHandle, _RTLP_IOWORKER_TCB::ThreadHandle, TimerThreadHandle, WaitThreads, _RTLP_WAIT_THREAD_CONTROL_BLOCK::WaitThreadsList, WorkerCompletionPort, and WorkerCriticalSection.

    01325                    :
    01326     This routine cleans up the thread pool.
    01327
    01328 Arguments:
    01329
    01330     None
    01331
    01332 Return Value:
    01333
    01334     STATUS_SUCCESS : if none of the components are in use.
    01335     STATUS_UNSUCCESSFUL : if some components are still in use.
    01336
    01337 --*/
    01338 {
    01339     BOOLEAN Cleanup ;
    01340     PLIST_ENTRY Node ;
    01341     ULONG i ;
    01342     HANDLE TmpHandle ;
    01343
    01344     return STATUS_UNSUCCESSFUL;
    01345
    01346     // cleanup timer thread
    01347
    01348     IS_COMPONENT_INITIALIZED(StartedTimerInitialization,
    01349                             CompletedTimerInitialization,
    01350                             Cleanup ) ;
    01351
    01352     if ( Cleanup ) {
    01353
    01354         ACQUIRE_GLOBAL_TIMER_LOCK() ;
    01355
    01356         if (NumTimerQueues != 0 ) {
    01357
    01358             ASSERTMSG( FALSE,
    01359                 "Trying to deinitialize ThreadPool when timers exist\n" ) ;
    01360             RELEASE_GLOBAL_TIMER_LOCK() ;
    01361
    01362             return STATUS_UNSUCCESSFUL ;
    01363         }
    01364
    01365         NtQueueApcThread(
    01366                 TimerThreadHandle,
    01367                 (PPS_APC_ROUTINE)RtlpThreadCleanup,
    01368                 NULL,
    01369                 NULL,
    01370                 NULL
    01371                 );
    01372
    01373         NtClose( TimerThreadHandle ) ;
    01374         TimerThreadHandle = NULL ;
    01375
    01376         RELEASE_GLOBAL_TIMER_LOCK() ;
    01377
    01378     }
    01379
    01380
    01381     //
    01382     // cleanup wait threads
    01383     //
    01384
    01385     IS_COMPONENT_INITIALIZED(StartedWaitInitialization,
    01386                             CompletedWaitInitialization,
    01387                             Cleanup ) ;
    01388
    01389     if ( Cleanup ) {
    01390
    01391         PRTLP_WAIT_THREAD_CONTROL_BLOCK ThreadCB ;
    01392
    01393         ACQUIRE_GLOBAL_WAIT_LOCK() ;
    01394
    01395         // Queue an APC to all Wait Threads
    01396
    01397         for (Node = WaitThreads.Flink ; Node != &WaitThreads ;
    01398                 Node = Node->Flink)
    01399         {
    01400
    01401             ThreadCB = CONTAINING_RECORD(Node,
    01402                                 RTLP_WAIT_THREAD_CONTROL_BLOCK,
    01403                                 WaitThreadsList) ;
    01404
    01405             if ( ThreadCB->NumWaits != 0 ) {
    01406
    01407                 ASSERTMSG( FALSE,
    01408                     "Cannot cleanup ThreadPool. Registered Wait events exist." ) ;
    01409                 RELEASE_GLOBAL_WAIT_LOCK( ) ;
    01410
    01411                 return STATUS_UNSUCCESSFUL ;
    01412             }
    01413
    01414             RemoveEntryList( &ThreadCB->WaitThreadsList ) ;
    01415             TmpHandle = ThreadCB->ThreadHandle ;
    01416
    01417             NtQueueApcThread(
    01418                     ThreadCB->ThreadHandle,
    01419                     (PPS_APC_ROUTINE)RtlpThreadCleanup,
    01420                     NULL,
    01421                     NULL,
    01422                     NULL
    01423                     );
    01424
    01425             NtClose( TmpHandle ) ;
    01426         }
    01427
    01428         RELEASE_GLOBAL_WAIT_LOCK( ) ;
    01429
    01430     }
    01431
    01432
    01433     // cleanup worker threads
    01434
    01435     IS_COMPONENT_INITIALIZED( StartedWorkerInitialization,
    01436                             CompletedWorkerInitialization,
    01437                             Cleanup ) ;
    01438
    01439     if ( Cleanup ) {
    01440
    01441         RtlEnterCriticalSection (&WorkerCriticalSection) ;
    01442
    01443         if ( (NumWorkRequests != 0) || (NumIOWorkRequests != 0) ) {
    01444
    01445             ASSERTMSG( FALSE,
    01446                 "Cannot cleanup ThreadPool. Work requests pending." ) ;
    01447
    01448             RtlLeaveCriticalSection (&WorkerCriticalSection) ;
    01449
    01450             return STATUS_UNSUCCESSFUL ;
    01451         }
    01452
    01453         // queue a cleanup for each worker thread
    01454
    01455         for (i = 0 ;  i < NumWorkerThreads ; i ++ ) {
    01456
    01457             NtSetIoCompletion (
    01458                     WorkerCompletionPort,
    01459                     RtlpThreadCleanup,
    01460                     NULL,
    01461                     STATUS_SUCCESS,
    01462                     0
    01463                     );
    01464         }
    01465
    01466         // queue an apc to cleanup all IO worker threads
    01467
    01468         for (Node = IOWorkerThreads.Flink ; Node != &IOWorkerThreads ;
    01469                 Node = Node->Flink )
    01470         {
    01471             PRTLP_IOWORKER_TCB ThreadCB ;
    01472
    01473             ThreadCB = CONTAINING_RECORD (Node, RTLP_IOWORKER_TCB, List) ;
    01474             RemoveEntryList( &ThreadCB->List) ;
    01475             TmpHandle = ThreadCB->ThreadHandle ;
    01476
    01477             NtQueueApcThread(
    01478                    ThreadCB->ThreadHandle,
    01479                    (PPS_APC_ROUTINE)RtlpThreadCleanup,
    01480                    NULL,
    01481                    NULL,
    01482                    NULL
    01483                    );
    01484
    01485             NtClose( TmpHandle ) ;
    01486         }
    01487
    01488         NumWorkerThreads = NumIOWorkerThreads = 0 ;
    01489
    01490         RtlLeaveCriticalSection (&WorkerCriticalSection) ;
    01491
    01492     }
    01493
    01494     return STATUS_SUCCESS ;
    01495
    01496 }

NTSTATUS RtlUpdateTimer | ( | IN HANDLE | TimerQueueHandle,
|  | IN HANDLE | Timer,
|  | IN ULONG | DueTime,
|  | IN ULONG | Period
| ) |

Definition at line 1058 of file threads.c.

References ASSERT, CHECK_DEL_SIGNATURE, DbgPrint, DPRN1, FALSE, NtQueueApcThread(), NTSTATUS(), NULL, PRTLP_TIMER, RTLP_TIMER, RtlpAllocateTPHeap, RtlpUpdateTimer(), Status, and TimerThreadHandle.

    01066                    :
    01067
    01068     This routine updates the timer
    01069
    01070 Arguments:
    01071
    01072     TimerQueueHandle - Handle identifying the queue in which the timer to be updated exists
    01073
    01074     Timer - Specifies a handle to the timer which needs to be updated
    01075
    01076     DueTime - Specifies the time in milliseconds after which the timer fires.
    01077
    01078     Period - Specifies the period of the timer in milliseconds. This should be
    01079             0 for one shot requests.
    01080
    01081 Return Value:
    01082
    01083     NTSTATUS - Result code from call.  The following are returned
    01084
    01085         STATUS_SUCCESS - Timer updated successfully.
    01086
    01087 --*/
    01088 {
    01089     NTSTATUS Status;
    01090     PRTLP_TIMER TmpTimer ;
    01091
    01092     if (!TimerQueueHandle || !Timer) {
    01093         ASSERT( FALSE ) ;
    01094         return STATUS_INVALID_PARAMETER ;
    01095     }
    01096
    01097     CHECK_DEL_SIGNATURE( (PRTLP_TIMER)Timer ) ;
    01098
    01099
    01100     TmpTimer = (PRTLP_TIMER) RtlpAllocateTPHeap (
    01101                                         sizeof (RTLP_TIMER),
    01102                                         0
    01103                                         ) ;
    01104
    01105     if (TmpTimer == NULL) {
    01106
    01107         return STATUS_NO_MEMORY ;
    01108     }
    01109
    01110     TmpTimer->DeltaFiringTime = DueTime;
    01111     //todo:remove below
    01112     if (Period==-1) Period = 0;
    01113     TmpTimer->Period = Period ;
    01114
    01115     #if DBG1
    01116     ((PRTLP_TIMER)Timer)->ThreadId2 =
    01117                     HandleToUlong(NtCurrentTeb()->ClientId.UniqueThread) ;
    01118     #endif
    01119     #if DBG1
    01120     if (DPRN1)
    01121     DbgPrint("<%d:%d:%d> Timer: updated by Thread:<%x:%x>\n\n",
    01122                 ((PRTLP_TIMER)Timer)->Queue->DbgId,
    01123                 ((PRTLP_TIMER)Timer)->DbgId, ((PRTLP_TIMER)Timer)->RefCount,
    01124                 HandleToUlong(NtCurrentTeb()->ClientId.UniqueThread),
    01125                 HandleToUlong(NtCurrentTeb()->ClientId.UniqueProcess)) ;
    01126     #endif
    01127
    01128
    01129     // queue APC to update timer
    01130
    01131     Status = NtQueueApcThread (
    01132                     TimerThreadHandle,
    01133                     (PPS_APC_ROUTINE)RtlpUpdateTimer,
    01134                     (PVOID)Timer, //Actual timer
    01135                     (PVOID)TmpTimer,
    01136                     NULL
    01137                     );
    01138
    01139
    01140     return Status ;
    01141 }

## Variable Documentation

ULONG DPRN = 0x0000000

| Definition at line 72 of file threads.c.