00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
#include <ntos.h>
00066
#include <ntrtl.h>
00067
#include <nturtl.h>
00068
#include "ntrtlp.h"
00069
#include "threads.h"
00070
00071
00072 ULONG
DPRN = 0x0000000;
00073
00074
00075
00076
NTSTATUS
00077 RtlRegisterWait (
00078 OUT PHANDLE WaitHandle,
00079 IN HANDLE Handle,
00080 IN WAITORTIMERCALLBACKFUNC Function,
00081 IN PVOID Context,
00082 IN ULONG Milliseconds,
00083 IN ULONG Flags
00084 )
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
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
00142
00143
if (
CompletedWaitInitialization != 1) {
00144
00145
Status =
RtlpInitializeWaitThreadPool () ;
00146
00147
if (!
NT_SUCCESS(
Status ) )
00148
return Status ;
00149 }
00150
00151
00152
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
00170
00171
00172
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
00196
00197 *WaitHandle = Wait ;
00198
00199
00200
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 }
00224
00225
00226
00227
NTSTATUS
00228 RtlDeregisterWait(
00229 IN HANDLE WaitHandle
00230 )
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250 {
00251
return RtlDeregisterWaitEx( WaitHandle,
NULL ) ;
00252 }
00253
00254
00255
NTSTATUS
00256 RtlDeregisterWaitEx(
00257 IN HANDLE WaitHandle,
00258 IN HANDLE Event
00259 )
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
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 ) ;
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
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
00347
00348
00349
if ( CurrentThreadId == Wait->ThreadCB->ThreadId ) {
00350
00351
Status =
RtlpDeregisterWait ( Wait,
NULL,
NULL ) ;
00352
00353
00354
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
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
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
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 }
00432
00433
00434
00435
00436
NTSTATUS
00437 RtlQueueWorkItem(
00438 IN WORKERCALLBACKFUNC Function,
00439 IN PVOID Context,
00440 IN ULONG Flags
00441 )
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474 {
00475 ULONG Threshold ;
00476 ULONG CurrentTickCount ;
00477
NTSTATUS Status = STATUS_SUCCESS ;
00478
00479
00480
00481
00482
if (
CompletedWorkerInitialization != 1) {
00483
00484
Status =
RtlpInitializeWorkerThreadPool () ;
00485
00486
if (!
NT_SUCCESS(
Status) )
00487
return Status ;
00488 }
00489
00490
00491
00492
00493 RtlEnterCriticalSection (&
WorkerCriticalSection) ;
00494
00495
00496
if (Flags & (WT_EXECUTEINIOTHREAD |WT_EXECUTEINUITHREAD |WT_EXECUTEINPERSISTENTIOTHREAD) ){
00497
00498
00499
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
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
00526
00527
Status =
RtlpStartIOWorkerThread () ;
00528
00529 }
00530
00531
if (
Status == STATUS_SUCCESS) {
00532
00533
00534
00535
Status =
RtlpQueueIOWorkerRequest (Function, Context, Flags) ;
00536 }
00537
00538
00539 }
else {
00540
00541
00542
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);
00551
00552
00553
00554
if (
NumMinWorkerThreads && NumEffWorkerThreads)
00555 NumEffWorkerThreads -- ;
00556
00557
00558
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
00576
00577
Status =
RtlpStartWorkerThread () ;
00578
00579 }
00580
00581
00582
00583
if (
Status == STATUS_SUCCESS) {
00584
00585
Status =
RtlpQueueWorkerRequest (Function, Context, Flags) ;
00586 }
00587
00588 }
00589
00590
00591
00592 RtlLeaveCriticalSection (&
WorkerCriticalSection) ;
00593
00594
return Status ;
00595 }
00596
00597
00598
00599
NTSTATUS
00600 RtlSetIoCompletionCallback (
00601 IN HANDLE FileHandle,
00602 IN APC_CALLBACK_FUNCTION CompletionProc,
00603 IN ULONG Flags
00604 )
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624 {
00625 IO_STATUS_BLOCK IoSb ;
00626 FILE_COMPLETION_INFORMATION CompletionInfo ;
00627
NTSTATUS Status;
00628
00629
00630
00631
00632
00633
if (
CompletedWorkerInitialization != 1) {
00634
00635
Status =
RtlpInitializeWorkerThreadPool () ;
00636
00637
if (!
NT_SUCCESS(
Status) )
00638
return Status ;
00639
00640 }
00641
00642
00643
00644
00645
00646
00647
00648
if (
NumMinWorkerThreads == 0 ) {
00649
00650
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
00666
NumMinWorkerThreads = 1 ;
00667
00668 RtlLeaveCriticalSection (&
WorkerCriticalSection) ;
00669
00670 }
00671
00672
00673
00674
00675 CompletionInfo.Port =
WorkerCompletionPort ;
00676 CompletionInfo.Key = (PVOID) CompletionProc ;
00677
00678
Status =
NtSetInformationFile (
00679 FileHandle,
00680 &IoSb,
00681 &CompletionInfo,
00682
sizeof(CompletionInfo),
00683 FileCompletionInformation
00684 ) ;
00685
return Status ;
00686 }
00687
00688
00689
00690
NTSTATUS
00691 RtlCreateTimerQueue(
00692 OUT PHANDLE TimerQueueHandle
00693 )
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712
00713
00714
00715
00716 {
00717
PRTLP_TIMER_QUEUE Queue ;
00718
NTSTATUS Status;
00719
00720
00721
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
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
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 }
00776
00777
00778
NTSTATUS
00779 RtlDeleteTimerQueue(
00780 IN HANDLE TimerQueueHandle
00781 )
00782
00783
00784
00785
00786
00787
00788
00789
00790
00791
00792
00793
00794
00795
00796
00797
00798
00799
00800
00801
00802
00803 {
00804
return RtlDeleteTimerQueueEx( TimerQueueHandle,
NULL ) ;
00805 }
00806
00807
00808
NTSTATUS
00809 RtlDeleteTimerQueueEx (
00810 HANDLE QueueHandle,
00811 HANDLE Event
00812 )
00813
00814
00815
00816
00817
00818
00819
00820
00821
00822
00823
00824
00825
00826
00827
00828
00829
00830
00831
00832
00833
00834
00835
00836
00837
00838
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
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
00885
00886
ACQUIRE_GLOBAL_TIMER_LOCK();
00887 Queue->State |=
STATE_DONTFIRE;
00888
RELEASE_GLOBAL_TIMER_LOCK();
00889
00890
00891
00892
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
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 }
00940
00941
00942
00943
NTSTATUS
00944 RtlCreateTimer(
00945 IN HANDLE TimerQueueHandle,
00946 OUT HANDLE *Handle,
00947 IN WAITORTIMERCALLBACKFUNC Function,
00948 IN PVOID Context,
00949 IN ULONG DueTime,
00950 IN ULONG Period,
00951 IN ULONG Flags
00952 )
00953
00954
00955
00956
00957
00958
00959
00960
00961
00962
00963
00964
00965
00966
00967
00968
00969
00970
00971
00972
00973
00974
00975
00976
00977
00978
00979
00980
00981
00982
00983
00984
00985
00986
00987
00988
00989
00990
00991
00992
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
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
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
01039
01040 InterlockedIncrement( &((
PRTLP_TIMER_QUEUE)TimerQueueHandle)->
RefCount ) ;
01041
01042
01043
01044
01045
Status =
NtQueueApcThread(
01046
TimerThreadHandle,
01047 (PPS_APC_ROUTINE)
RtlpAddTimer,
01048 (PVOID)Timer,
01049
NULL,
01050
NULL
01051 ) ;
01052
01053
return Status ;
01054 }
01055
01056
01057
NTSTATUS
01058 RtlUpdateTimer(
01059 IN HANDLE TimerQueueHandle,
01060 IN HANDLE Timer,
01061 IN ULONG DueTime,
01062 IN ULONG Period
01063 )
01064
01065
01066
01067
01068
01069
01070
01071
01072
01073
01074
01075
01076
01077
01078
01079
01080
01081
01082
01083
01084
01085
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
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
01130
01131
Status =
NtQueueApcThread (
01132
TimerThreadHandle,
01133 (PPS_APC_ROUTINE)
RtlpUpdateTimer,
01134 (PVOID)Timer,
01135 (PVOID)TmpTimer,
01136
NULL
01137 );
01138
01139
01140
return Status ;
01141 }
01142
01143
01144
NTSTATUS
01145 RtlDeleteTimer (
01146 IN HANDLE TimerQueueHandle,
01147 IN HANDLE TimerToCancel,
01148 IN HANDLE Event
01149 )
01150
01151
01152
01153
01154
01155
01156
01157
01158
01159
01160
01161
01162
01163
01164
01165
01166
01167
01168
01169
01170
01171
01172
01173
01174
01175
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
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
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 }
01285
01286
01287
01288
01289
NTSTATUS
01290 NTAPI
01291 RtlSetThreadPoolStartFunc(
01292 PRTLP_START_THREAD StartFunc,
01293 PRTLP_EXIT_THREAD ExitFunc
01294 )
01295
01296
01297
01298
01299
01300
01301
01302
01303
01304
01305
01306
01307
01308
01309
01310
01311 {
01312
RtlpStartThreadFunc = StartFunc ;
01313
RtlpExitThreadFunc = ExitFunc ;
01314
return STATUS_SUCCESS ;
01315 }
01316
01317
01318
01319
NTSTATUS
01320 RtlThreadPoolCleanup (
01321 ULONG Flags
01322 )
01323
01324
01325
01326
01327
01328
01329
01330
01331
01332
01333
01334
01335
01336
01337
01338 {
01339 BOOLEAN Cleanup ;
01340 PLIST_ENTRY Node ;
01341 ULONG i ;
01342 HANDLE TmpHandle ;
01343
01344
return STATUS_UNSUCCESSFUL;
01345
01346
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
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
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
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
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
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 }
01497
01498
01499
01500
01501
01502
01503
01504
01505
NTSTATUS
01506 RtlpQueueWorkerRequest (
01507 WORKERCALLBACKFUNC Function,
01508 PVOID Context,
01509 ULONG Flags
01510 )
01511
01512
01513
01514
01515
01516
01517
01518
01519
01520
01521
01522
01523
01524
01525
01526
01527
01528
01529 {
01530
NTSTATUS Status ;
01531
PRTLP_WORK WorkEntry ;
01532
01533
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
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 }
01586
01587
01588
VOID
01589 RtlpExecuteWorkerRequest (
01590 NTSTATUS Status,
01591 PVOID Context,
01592 PVOID WorkContext
01593 )
01594
01595
01596
01597
01598
01599
01600
01601
01602
01603
01604
01605
01606
01607
01608
01609
01610
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
01626 }
01627
01628 InterlockedDecrement( &
NumWorkRequests ) ;
01629
if (WorkEntry->
Flags & WT_EXECUTELONGFUNCTION) {
01630 InterlockedDecrement( &
NumLongWorkRequests ) ;
01631 }
01632
01633
RtlpFreeTPHeap( WorkEntry ) ;
01634 }
01635
01636
01637
NTSTATUS
01638 RtlpQueueIOWorkerRequest (
01639 WORKERCALLBACKFUNC Function,
01640 PVOID Context,
01641 ULONG Flags
01642 )
01643
01644
01645
01646
01647
01648
01649
01650
01651
01652
01653
01654
01655
01656
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
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
01695
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
01719
01720 LongFunction =
FALSE;
01721 }
01722
01723
01724
01725
01726 RemoveEntryList (&TCB->
List) ;
01727 InsertTailList (&
IOWorkerThreads, &TCB->
List) ;
01728 }
01729
01730
01731
01732
01733 InterlockedIncrement (&
NumIOWorkRequests) ;
01734
if (LongFunction) {
01735 InterlockedIncrement( &
NumLongIOWorkRequests ) ;
01736 TCB->
LongFunctionFlag =
TRUE ;
01737 }
01738
01739
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 }
01759
01760
01761
01762
NTSTATUS
01763 RtlpStartWorkerThread (
01764 )
01765
01766
01767
01768
01769
01770
01771
01772
01773
01774
01775
01776
01777
01778
01779
01780 {
01781 HANDLE
ThreadHandle ;
01782 ULONG CurrentTickCount ;
01783
NTSTATUS Status ;
01784
01785
01786
01787
Status =
RtlpStartThreadFunc (
RtlpWorkerThread, &
ThreadHandle) ;
01788
01789
if (
Status == STATUS_SUCCESS ) {
01790
01791
01792
01793
LastThreadCreationTickCount =
NtGetTickCount() ;
01794
01795
01796
01797 InterlockedIncrement(&
NumWorkerThreads) ;
01798
01799
01800
01801
NtClose (
ThreadHandle) ;
01802
01803 }
else {
01804
01805
01806
01807
01808
if (
NumWorkerThreads == 0) {
01809
01810
return Status ;
01811 }
01812
01813 }
01814
01815
return STATUS_SUCCESS ;
01816 }
01817
01818
01819
NTSTATUS
01820 RtlpStartIOWorkerThread (
01821 )
01822
01823
01824
01825
01826
01827
01828
01829
01830
01831
01832
01833
01834
01835
01836
01837 {
01838 HANDLE
ThreadHandle ;
01839 ULONG CurrentTickCount ;
01840
NTSTATUS Status ;
01841
01842
01843
01844
01845
Status =
RtlpStartThreadFunc (
RtlpIOWorkerThread, &
ThreadHandle) ;
01846
01847
if (
Status == STATUS_SUCCESS ) {
01848
01849
NtClose(
ThreadHandle ) ;
01850
01851
01852
01853
LastThreadCreationTickCount =
NtGetTickCount() ;
01854
01855 }
else {
01856
01857
01858
01859
01860
if (
NumIOWorkerThreads == 0) {
01861
01862
return Status ;
01863
01864 }
01865 }
01866
01867
return STATUS_SUCCESS ;
01868 }
01869
01870
01871
VOID
01872 RtlpWorkerThreadTimerCallback(
01873 PVOID Context,
01874 BOOLEAN NotUsed
01875 )
01876
01877
01878
01879
01880
01881
01882
01883
01884
01885
01886
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
01919
01920
01921
01922
01923
01924
if (
TotalExecutedWorkRequests ==
OldTotalExecutedWorkRequests) {
01925
01926 bCreateThread =
TRUE ;
01927 }
01928
01929
01930
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 }
01961
01962
01963
01964
NTSTATUS
01965 RtlpInitializeWorkerThreadPool (
01966 )
01967
01968
01969
01970
01971
01972
01973
01974
01975
01976
01977
01978
01979
01980
01981
01982 {
01983
NTSTATUS Status = STATUS_SUCCESS ;
01984 LARGE_INTEGER TimeOut ;
01985
01986
01987
01988
01989
if (
CompletedTimerInitialization != 1) {
01990
01991
Status =
RtlpInitializeTimerThreadPool () ;
01992
01993
if ( !
NT_SUCCESS(
Status) )
01994
return Status ;
01995
01996 }
01997
01998
01999
02000
02001
02002
02003
02004
02005
if (!InterlockedExchange(&
StartedWorkerInitialization, 1
L)) {
02006
02007
if (
CompletedWorkerInitialization)
02008 InterlockedExchange( &
CompletedWorkerInitialization, 0 ) ;
02009
02010
02011
do {
02012
02013
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
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
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
02063
02064 InterlockedExchange (&
CompletedWorkerInitialization, 1
L) ;
02065
02066 }
else {
02067
02068 LARGE_INTEGER Timeout ;
02069
02070
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
02087
02088
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 }
02100
02101
02102
02103
VOID
02104 RtlpWorkerThreadInitializeTimers(
02105 PVOID Context
02106 )
02107 {
02108
NTSTATUS Status;
02109
02110
02111
02112
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 }
02130
02131
02132
02133
02134
02135
02136 LONG
02137 RtlpWorkerThread (
02138 PVOID Initialized
02139 )
02140
02141
02142
02143
02144
02145
02146
02147
02148
02149
02150
02151
02152
02153
02154
02155
02156
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
02171
02172 InterlockedExchange ((ULONG *)
Initialized, 1
L) ;
02173
02174
02175
02176
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
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 ++ ;
02201 InterlockedIncrement(&
NumExecutingWorkerThreads) ;
02202
02203
02204
02205
02206
02207
02208
02209 Context = (PVOID) IoSb.Information ;
02210
02211
try {
02212 ((APC_CALLBACK_FUNCTION)WorkerProc) (
02213 IoSb.Status,
02214 Context,
02215 Overlapped
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
02228
02229
02230 Terminate =
FALSE ;
02231
02232 RtlEnterCriticalSection (&
WorkerCriticalSection) ;
02233
02234
02235
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
02249
02250
02251
02252
02253
02254
if (NumEffWorkerThreads > 1)
02255 Terminate =
TRUE ;
02256
02257 }
else {
02258
02259 ULONG Threshold ;
02260
02261
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
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
02348
02349
02350
02351 RtlLeaveCriticalSection (&
WorkerCriticalSection) ;
02352
02353 }
02354
02355 }
else {
02356
02357
ASSERT (
FALSE) ;
02358
02359 }
02360
02361 }
02362
02363
02364
return 1 ;
02365 }
02366
02367
02368
02369 LONG
02370 RtlpIOWorkerThread (
02371 PVOID Initialized
02372 )
02373
02374
02375
02376
02377
02378
02379
02380
02381
02382
02383
02384
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 ;
02393
NTSTATUS Status ;
02394 BOOLEAN Terminate ;
02395
02396
02397
02398
02399
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
02426
02427 InterlockedExchange ((ULONG *)
Initialized, 1
L) ;
02428
02429
02430
02431
02432
02433
02434
for ( ; ; ) {
02435
02436
02437
02438 TimeOut.QuadPart = Int32x32To64( SleepTime, -10000 ) ;
02439
02440
02441
Status =
NtDelayExecution (
TRUE, &TimeOut) ;
02442
02443
02444
02445
02446
if (
Status != STATUS_SUCCESS) {
02447
continue ;
02448 }
02449
02450
02451
02452
02453
02454
02455 Terminate =
FALSE ;
02456
02457 RtlEnterCriticalSection (&
WorkerCriticalSection) ;
02458
02459
02460
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
02474
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
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
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
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
02568
02569
02570
02571 RtlLeaveCriticalSection (&
WorkerCriticalSection) ;
02572
02573 }
02574 }
02575
02576
return 0 ;
02577
02578 }
02579
02580
02581
02582
VOID
02583 RtlpExecuteLongIOWorkItem (
02584 PVOID Function,
02585 PVOID Context,
02586 PVOID ThreadCB
02587 )
02588
02589
02590
02591
02592
02593
02594
02595
02596
02597
02598
02599
02600
02601
02602
02603
02604
02605 {
02606
#if (DBG1)
02607
DBG_SET_FUNCTION( Function, Context ) ;
02608
#endif
02609
02610
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
02622
02623 InterlockedDecrement (&
NumIOWorkRequests) ;
02624
02625
02626
02627 InterlockedDecrement (&
NumLongIOWorkRequests ) ;
02628 }
02629
02630
02631
VOID
02632 RtlpExecuteIOWorkItem (
02633 PVOID Function,
02634 PVOID Context,
02635 PVOID NotUsed
02636 )
02637
02638
02639
02640
02641
02642
02643
02644
02645
02646
02647
02648
02649
02650
02651
02652
02653
02654
02655 {
02656
#if (DBG1)
02657
DBG_SET_FUNCTION( Function, Context ) ;
02658
#endif
02659
02660
02661
02662
try {
02663 ((WORKERCALLBACKFUNC) Function)((PVOID)Context) ;
02664 } except (
EXCEPTION_EXECUTE_HANDLER) {
02665
ASSERT(
FALSE);
02666 }
02667
02668
02669
02670 InterlockedDecrement (&
NumIOWorkRequests) ;
02671
02672 }
02673
02674
02675
NTSTATUS
02676 NTAPI
02677 RtlpStartThread (
02678 PUSER_THREAD_START_ROUTINE Function,
02679 HANDLE *ThreadHandle
02680 )
02681
02682
02683
02684
02685
02686
02687
02688
02689
02690
02691
02692
02693
02694
02695
02696
02697 {
02698
NTSTATUS Status ;
02699 ULONG
Initialized ;
02700 LARGE_INTEGER TimeOut ;
02701
02702
Initialized =
FALSE ;
02703
02704
02705
02706
Status =
RtlCreateUserThread(
02707 NtCurrentProcess(),
02708
NULL,
02709
FALSE,
02710 0
L,
02711 0
L,
02712 0
L,
02713 Function,
02714 &
Initialized,
02715
ThreadHandle,
02716
NULL
02717 );
02718
02719
if (
Status == STATUS_SUCCESS ) {
02720
02721
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 }
02736
02737
NTSTATUS
02738 RtlpExitThread(
02739 NTSTATUS Status
02740 )
02741 {
02742
return NtTerminateThread( NtCurrentThread(),
Status );
02743 }
02744
02745
02746
02747
02748
02749
02750
NTSTATUS
02751 RtlpInitializeWaitThreadPool (
02752 )
02753
02754
02755
02756
02757
02758
02759
02760
02761
02762
02763
02764
02765
02766
02767
02768 {
02769
NTSTATUS Status = STATUS_SUCCESS;
02770 LARGE_INTEGER TimeOut ;
02771
02772
02773
02774
02775
02776
02777
02778
if (!InterlockedExchange(&
StartedWaitInitialization, 1
L)) {
02779
02780
if (
CompletedWaitInitialization)
02781 InterlockedExchange (&
CompletedWaitInitialization, 0
L) ;
02782
02783
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);
02798
02799 InterlockedExchange (&
CompletedWaitInitialization, 1
L) ;
02800
02801 }
else {
02802
02803
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 }
02820
02821
02822
02823 LONG
02824 RtlpWaitThread (
02825 PVOID Initialized
02826 )
02827
02828
02829
02830
02831
02832
02833
02834
02835
02836
02837
02838
02839
02840
02841
02842 {
02843 ULONG i ;
02844
NTSTATUS Status ;
02845 LARGE_INTEGER TimeOut;
02846
PRTLP_WAIT_THREAD_CONTROL_BLOCK ThreadCB ;
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
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
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
02912
02913
RtlpResetTimer (ThreadCB->
TimerHandle, -1, ThreadCB) ;
02914
02915 InitializeListHead (&ThreadCB->
TimerQueue.TimerList) ;
02916 InitializeListHead (&ThreadCB->
TimerQueue.UncancelledTimerList) ;
02917
02918
02919
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
02934
02935
02936 InsertHeadList (&
WaitThreads, &ThreadCB->
WaitThreadsList) ;
02937
02938
02939
02940
02941 ThreadCB->
ActiveWaitArray[0] = ThreadCB->
TimerHandle ;
02942
02943 ThreadCB->
NumActiveWaits = ThreadCB->
NumWaits = 1 ;
02944
02945
02946
02947
02948
02949
02950
02951
02952 InterlockedExchange ((ULONG *)
Initialized, 1) ;
02953
02954
02955
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,
02967 ThreadCB->
NumWaits!=1 ?
NULL : &TimeOut
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
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
02999
03000
ASSERT (
FALSE) ;
03001
03002 }
else if (
Status == STATUS_TIMEOUT) {
03003
03004
03005
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
03032 ULONG i ;
03033
03034
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,
03051 &TimeOut
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
03066
03067 TimeOut.LowPart = 0 ;
03068 TimeOut.HighPart = 0x80000000 ;
03069
03070
NtDelayExecution (
TRUE, &TimeOut) ;
03071
03072 }
03073
03074 }
03075
03076
return 0 ;
03077
03078 }
03079
03080
03081
VOID
03082 RtlpAsyncCallbackCompletion(
03083 PVOID Context
03084 )
03085
03086
03087
03088
03089
03090
03091
03092
03093
03094
03095
03096
03097
03098
03099 {
03100
PRTLP_ASYNC_CALLBACK AsyncCallback ;
03101
03102 AsyncCallback = (
PRTLP_ASYNC_CALLBACK) Context ;
03103
03104
03105
03106
if ( AsyncCallback->
WaitThreadCallback ) {
03107
03108
PRTLP_WAIT Wait = AsyncCallback->
Wait ;
03109
03110
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
03134
03135
else {
03136
03137
PRTLP_TIMER Timer = AsyncCallback->
Timer ;
03138
03139
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
03157
03158
if ( InterlockedDecrement( &Timer->RefCount ) == 0 ) {
03159
03160
RtlpDeleteTimer( Timer ) ;
03161 }
03162
03163 }
03164
03165
03166
RtlpFreeTPHeap( AsyncCallback );
03167
03168 }
03169
03170
03171
VOID
03172 RtlpProcessWaitCompletion (
03173
PRTLP_WAIT Wait,
03174 ULONG ArrayIndex
03175 )
03176
03177
03178
03179
03180
03181
03182
03183
03184
03185
03186
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
03199
03200
if ( Wait->
Flags & WT_EXECUTEONLYONCE ) {
03201
03202
RtlpDeactivateWait (Wait) ;
03203 }
03204
03205
else {
03206
03207
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
03221
03222
03223
RtlpResetTimer (ThreadCB->
TimerHandle, NewFiringTime, ThreadCB) ;
03224 }
03225
03226 }
03227
03228
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
03241
03242
if ( Wait->
Flags & WT_EXECUTEINWAITTHREAD ) {
03243
03244
03245
03246
03247
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
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 }
03299
03300
03301
VOID
03302 RtlpAddWait (
03303
PRTLP_WAIT Wait
03304 )
03305
03306
03307
03308
03309
03310
03311
03312
03313
03314
03315
03316
03317
03318
03319 {
03320
PRTLP_WAIT_THREAD_CONTROL_BLOCK ThreadCB = Wait->
ThreadCB;
03321
03322
03323
03324
03325
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
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
03349
03350
if (Wait->
Timeout !=
INFINITE_TIME) {
03351
03352 ULONG TimeRemaining ;
03353 ULONG NewFiringTime ;
03354
03355
03356
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
03380
03381
RtlpResetTimer (ThreadCB->
TimerHandle, NewFiringTime, ThreadCB) ;
03382 }
03383
03384 }
else {
03385
03386
03387
03388 Wait->
Timer =
NULL ;
03389
03390 }
03391
03392
return ;
03393 }
03394
03395
03396
NTSTATUS
03397 RtlpDeregisterWait (
03398
PRTLP_WAIT Wait,
03399 HANDLE PartialCompletionEvent,
03400 PULONG RetStatusPtr
03401 )
03402
03403
03404
03405
03406
03407
03408
03409
03410
03411
03412
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
03424
03425
03426
03427
03428
if ( ! (Wait->
State &
STATE_REGISTERED) ) {
03429
03430
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
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
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 }
03480
03481
03482
NTSTATUS
03483 RtlpDeactivateWait (
03484
PRTLP_WAIT Wait
03485 )
03486
03487
03488
03489
03490
03491
03492
03493
03494
03495
03496
03497
03498
03499 {
03500
PRTLP_WAIT_THREAD_CONTROL_BLOCK ThreadCB = Wait->
ThreadCB ;
03501 ULONG ArrayIndex ;
03502 ULONG EndIndex = ThreadCB->
NumActiveWaits -1;
03503
03504
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
03520
03521
RtlpShiftWaitArray( ThreadCB, ArrayIndex+1, ArrayIndex,
03522 EndIndex - ArrayIndex ) ;
03523
03524
03525
03526
03527
03528
03529
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
03561
03562 ThreadCB->
NumActiveWaits-- ;
03563 InterlockedDecrement( &ThreadCB->
NumWaits ) ;
03564
03565 Wait->
State &= ~
STATE_ACTIVE ;
03566
03567
return STATUS_SUCCESS;
03568
03569 }
03570
03571
03572
VOID
03573 RtlpDeleteWait (
03574
PRTLP_WAIT Wait
03575 )
03576
03577
03578
03579
03580
03581
03582
03583
03584
03585
03586
03587
03588
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 }
03612
03613
03614
03615
03616
VOID
03617 RtlpDoNothing (
03618 PVOID NotUsed1,
03619 PVOID NotUsed2,
03620 PVOID NotUsed3
03621 )
03622
03623
03624
03625
03626
03627
03628
03629
03630
03631
03632
03633
03634
03635
03636
03637 {
03638
03639 }
03640
03641
03642 __inline
03643 LONGLONG
03644 RtlpGet64BitTickCount(
03645 LARGE_INTEGER *Last64BitTickCount
03646 )
03647
03648
03649
03650
03651
03652
03653
03654
03655
03656
03657
03658 {
03659 LARGE_INTEGER liCurTime ;
03660
03661 liCurTime.QuadPart =
NtGetTickCount() +
Last64BitTickCount->HighPart ;
03662
03663
03664
03665
if (liCurTime.LowPart <
Last64BitTickCount->LowPart) {
03666 liCurTime.HighPart++ ;
03667 }
03668
03669
return (
Last64BitTickCount->QuadPart = liCurTime.QuadPart) ;
03670 }
03671
03672 __inline
03673 LONGLONG
03674 RtlpResync64BitTickCount(
03675 )
03676
03677
03678
03679
03680
03681
03682
03683
03684
03685
03686
03687
03688
03689
03690 {
03691
return Resync64BitTickCount.QuadPart =
03692
RtlpGet64BitTickCount(&
Last64BitTickCount);
03693 }
03694
03695
03696
VOID
03697 RtlpProcessTimeouts (
03698
PRTLP_WAIT_THREAD_CONTROL_BLOCK ThreadCB
03699 )
03700
03701
03702
03703
03704
03705
03706
03707
03708
03709
03710
03711
03712
03713 {
03714 ULONG NewFiringTime, TimeRemaining ;
03715 LIST_ENTRY TimersToFireList ;
03716
03717
03718
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
03734
03735
RtlpFireTimersAndReorder (&ThreadCB->
TimerQueue, &NewFiringTime, &TimersToFireList) ;
03736
03737
03738
03739
RtlpResetTimer (ThreadCB->
TimerHandle, NewFiringTime, ThreadCB) ;
03740
03741
03742
RtlpFireTimers( &TimersToFireList ) ;
03743 }
03744
03745
03746
VOID
03747 RtlpFireTimers (
03748 PLIST_ENTRY TimersToFireList
03749 )
03750
03751
03752
03753
03754
03755
03756
03757
03758
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
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
03802
03803
PRTLP_ASYNC_CALLBACK AsyncCallback ;
03804
03805 AsyncCallback =
RtlpForceAllocateTPHeap(
03806
sizeof(
RTLP_ASYNC_CALLBACK ),
03807 0 );
03808 AsyncCallback->
TimerCondition =
TRUE ;
03809
03810
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
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 }
03848
03849
03850
NTSTATUS
03851 RtlpFindWaitThread (
03852
PRTLP_WAIT_THREAD_CONTROL_BLOCK *ThreadCB
03853 )
03854
03855
03856
03857
03858
03859
03860
03861
03862
03863
03864
03865
03866
03867
03868
03869
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
03884
03885
03886
03887
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
03897
03898
if ((ThreadCBTmp)->NumWaits < 64) {
03899
03900
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
03915
03916
Status =
RtlpStartThreadFunc (
RtlpWaitThread, &
ThreadHandle) ;
03917
03918
03919
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
03934
03935
NtClose (
ThreadHandle) ;
03936 }
03937
03938
03939
03940 }
while (
TRUE) ;
03941
03942
RELEASE_GLOBAL_WAIT_LOCK() ;
03943
03944
return Status ;
03945 }
03946
03947
03948
03949
03950
03951
03952
03953
VOID
03954 RtlpAddTimer (
03955 PRTLP_TIMER Timer
03956 )
03957
03958
03959
03960
03961
03962
03963
03964
03965
03966
03967
03968
03969
03970
03971
03972 {
03973
PRTLP_TIMER_QUEUE Queue ;
03974 ULONG TimeRemaining, QueueRelTimeRemaining ;
03975 ULONG NewFiringTime ;
03976
03977
RtlpResync64BitTickCount() ;
03978
03979
03980
03981
03982
if (Timer->State &
STATE_DELETE ) {
03983
03984
RtlpDeleteTimer( Timer ) ;
03985
return ;
03986 }
03987
03988
03989 Queue = Timer->Queue ;
03990
03991
03992
03993
03994
03995 TimeRemaining =
RtlpGetTimeRemaining (
TimerHandle) ;
03996 QueueRelTimeRemaining = TimeRemaining +
RtlpGetQueueRelativeTime (Queue) ;
03997
03998
03999
if (
RtlpInsertInDeltaList (&Queue->TimerList, Timer, QueueRelTimeRemaining,
04000 &NewFiringTime))
04001 {
04002
04003
04004
04005
04006
04007
if (IsListEmpty (&Queue->List)) {
04008
04009 Queue->DeltaFiringTime = NewFiringTime ;
04010
04011
if (
RtlpInsertInDeltaList (&
TimerQueues, Queue, TimeRemaining,
04012 &NewFiringTime))
04013 {
04014
04015
04016
04017
04018
RtlpResetTimer (
TimerHandle, NewFiringTime,
NULL) ;
04019 }
04020
04021 }
else {
04022
04023
04024
04025
04026
if (
RtlpReOrderDeltaList(&
TimerQueues, Queue, TimeRemaining, &NewFiringTime, NewFiringTime)){
04027
04028
04029
04030
04031
RtlpResetTimer (
TimerHandle, NewFiringTime,
NULL) ;
04032
04033 }
04034 }
04035
04036 }
04037
04038 Timer->State |= (
STATE_REGISTERED |
STATE_ACTIVE ) ;
04039 }
04040
04041
04042
04043
VOID
04044 RtlpUpdateTimer (
04045 PRTLP_TIMER Timer,
04046 PRTLP_TIMER UpdatedTimer
04047 )
04048
04049
04050
04051
04052
04053
04054
04055
04056
04057
04058
04059
04060
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
04077
04078 Timer->Period = UpdatedTimer->Period ;
04079
04080
04081
04082
04083
if ( ! ( Timer->State &
STATE_ACTIVE ) ) {
04084
04085
return ;
04086 }
04087
04088
04089
04090 TimeRemaining =
RtlpGetTimeRemaining (
TimerHandle) ;
04091 QueueRelTimeRemaining = TimeRemaining +
RtlpGetQueueRelativeTime (Queue) ;
04092
04093
04094
04095
04096
if (
RtlpReOrderDeltaList (&Queue->TimerList, Timer, QueueRelTimeRemaining,
04097 &NewFiringTime,
04098 UpdatedTimer->DeltaFiringTime))
04099 {
04100
04101
04102
04103
04104
if (
RtlpReOrderDeltaList (&
TimerQueues, Queue, TimeRemaining, &NewFiringTime, NewFiringTime)) {
04105
04106
04107
04108
04109
RtlpResetTimer (
TimerHandle, NewFiringTime,
NULL) ;
04110
04111 }
04112
04113 }
04114
04115
RtlpFreeTPHeap( UpdatedTimer ) ;
04116 }
04117
04118
04119
VOID
04120 RtlpCancelTimer (
04121 PRTLP_TIMER Timer
04122 )
04123
04124
04125
04126
04127
04128
04129
04130
04131
04132
04133
04134
04135
04136
04137 {
04138
RtlpCancelTimerEx( Timer,
FALSE ) ;
04139 }
04140
04141
VOID
04142 RtlpCancelTimerEx (
04143 PRTLP_TIMER Timer,
04144 BOOLEAN DeletingQueue
04145 )
04146
04147
04148
04149
04150
04151
04152
04153
04154
04155
04156
04157
04158
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
04174
04175
if ( ! DeletingQueue )
04176
RtlpDeactivateTimer( Queue, Timer ) ;
04177
04178 }
else {
04179
04180
04181
04182
04183 RemoveEntryList( &Timer->List ) ;
04184
04185 }
04186
04187
04188
04189
04190 Timer->State |=
STATE_DELETE ;
04191
04192
04193
04194
04195
if ( InterlockedDecrement( &Timer->RefCount ) == 0 ) {
04196
04197
RtlpDeleteTimer( Timer ) ;
04198 }
04199 }
04200
04201
VOID
04202 RtlpDeactivateTimer (
04203 PRTLP_TIMER_QUEUE Queue,
04204 PRTLP_TIMER Timer
04205 )
04206
04207
04208
04209
04210
04211
04212
04213
04214
04215
04216
04217
04218
04219
04220 {
04221 ULONG TimeRemaining, QueueRelTimeRemaining ;
04222 ULONG NewFiringTime ;
04223
04224
04225
04226
04227 TimeRemaining =
RtlpGetTimeRemaining (
TimerHandle) ;
04228 QueueRelTimeRemaining = TimeRemaining +
RtlpGetQueueRelativeTime (Queue) ;
04229
04230
if (
RtlpRemoveFromDeltaList (&Queue->TimerList, Timer, QueueRelTimeRemaining, &NewFiringTime)) {
04231
04232
04233
04234
04235
if (IsListEmpty (&Queue->TimerList)) {
04236
04237
04238
04239
if (
RtlpRemoveFromDeltaList (&
TimerQueues, Queue, TimeRemaining, &NewFiringTime)) {
04240
04241
04242
04243
04244
RtlpResetTimer (
TimerHandle, NewFiringTime,
NULL) ;
04245
04246 }
04247
04248 InitializeListHead (&Queue->List) ;
04249
04250 }
else {
04251
04252
04253
04254
04255
if (
RtlpReOrderDeltaList (&
TimerQueues, Queue, TimeRemaining, &NewFiringTime, NewFiringTime)) {
04256
04257
04258
04259
04260
RtlpResetTimer (
TimerHandle, NewFiringTime,
NULL) ;
04261
04262 }
04263
04264 }
04265
04266 }
04267 }
04268
04269
04270
VOID
04271 RtlpDeleteTimer (
04272 PRTLP_TIMER Timer
04273 )
04274
04275
04276
04277
04278
04279
04280
04281
04282
04283
04284
04285
04286
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
04303
04304
04305
04306 RemoveEntryList( &Timer->TimersToFireList ) ;
04307
04308
if ( Timer->CompletionEvent )
04309
NtSetEvent( Timer->CompletionEvent,
NULL ) ;
04310
04311
04312
04313
04314
if ( InterlockedDecrement( &Queue->RefCount ) == 0 )
04315
04316
RtlpDeleteTimerQueueComplete( Queue ) ;
04317
04318
04319
RtlpFreeTPHeap( Timer ) ;
04320
04321 }
04322
04323
04324
04325 ULONG
04326 RtlpGetQueueRelativeTime (
04327 PRTLP_TIMER_QUEUE Queue
04328 )
04329
04330
04331
04332
04333
04334
04335
04336
04337
04338
04339
04340
04341
04342
04343
04344
04345 {
04346 PLIST_ENTRY Node ;
04347 ULONG RelativeTime ;
04348
PRTLP_TIMER_QUEUE CurrentQueue ;
04349
04350 RelativeTime = 0 ;
04351
04352
04353
04354
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
04367
04368 RelativeTime += Queue->DeltaFiringTime ;
04369
04370 }
04371
04372
return RelativeTime ;
04373
04374 }
04375
04376
04377 ULONG
04378 RtlpGetTimeRemaining (
04379 HANDLE TimerHandle
04380 )
04381
04382
04383
04384
04385
04386
04387
04388
04389
04390
04391
04392
04393
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
04407
04408
04409
04410
04411
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 }
04425
04426
04427
04428
VOID
04429 RtlpResetTimer (
04430 HANDLE TimerHandle,
04431 ULONG DueTime,
04432
PRTLP_WAIT_THREAD_CONTROL_BLOCK ThreadCB
04433 )
04434
04435
04436
04437
04438
04439
04440
04441
04442
04443
04444
04445
04446
04447
04448
04449 {
04450 LARGE_INTEGER LongDueTime ;
04451
04452
NtCancelTimer (
TimerHandle,
NULL) ;
04453
04454
04455
04456
if (DueTime ==
INFINITE_TIME) {
04457
04458 LongDueTime.LowPart = 0x0 ;
04459
04460 LongDueTime.HighPart = 0x80000000 ;
04461
04462 }
else {
04463
04464
04465
04466
04467
04468
if (ThreadCB) {
04469
04470 ThreadCB->
Firing64BitTickCount = DueTime
04471 +
RtlpGet64BitTickCount(&ThreadCB->
Current64BitTickCount) ;
04472
04473 }
else {
04474
04475
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 }
04504
04505
04506 BOOLEAN
04507 RtlpInsertInDeltaList (
04508 PLIST_ENTRY DeltaList,
04509
PRTLP_GENERIC_TIMER NewTimer,
04510 ULONG TimeRemaining,
04511 ULONG *NewFiringTime
04512 )
04513
04514
04515
04516
04517
04518
04519
04520
04521
04522
04523
04524
04525
04526
04527
04528
04529
04530
04531
04532
04533
04534
04535
04536
04537
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
04558
04559 Head = CONTAINING_RECORD (DeltaList->Flink,
RTLP_GENERIC_TIMER,
List) ;
04560
04561 Head->
DeltaFiringTime += TimeRemaining ;
04562
04563
04564
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
04578
04579
break ;
04580
04581 }
04582
04583 }
04584
04585
04586
04587
04588 InsertHeadList (Node->Blink, &NewTimer->
List) ;
04589
04590
04591
04592
04593
04594
if (Node != DeltaList) {
04595
04596 Temp->
DeltaFiringTime -= NewTimer->
DeltaFiringTime ;
04597
04598 }
04599
04600
04601
04602
04603
if (DeltaList->Flink == &NewTimer->
List) {
04604
04605
04606
04607
04608 *NewFiringTime = NewTimer->
DeltaFiringTime ;
04609
04610
04611
04612 NewTimer->
DeltaFiringTime = 0 ;
04613
04614
return TRUE ;
04615
04616 }
else {
04617
04618
04619
04620 Head->
DeltaFiringTime -= TimeRemaining ;
04621
04622
return FALSE ;
04623
04624 }
04625
04626 }
04627
04628
04629
04630 BOOLEAN
04631 RtlpRemoveFromDeltaList (
04632 PLIST_ENTRY DeltaList,
04633
PRTLP_GENERIC_TIMER Timer,
04634 ULONG TimeRemaining,
04635 ULONG* NewFiringTime
04636 )
04637
04638
04639
04640
04641
04642
04643
04644
04645
04646
04647
04648
04649
04650
04651
04652
04653
04654
04655
04656
04657
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
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
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 }
04707
04708
04709
04710 BOOLEAN
04711 RtlpReOrderDeltaList (
04712 PLIST_ENTRY DeltaList,
04713
PRTLP_GENERIC_TIMER Timer,
04714 ULONG TimeRemaining,
04715 ULONG *NewFiringTime,
04716 ULONG ChangedFiringTime
04717 )
04718
04719
04720
04721
04722
04723
04724
04725
04726
04727
04728
04729
04730
04731
04732
04733
04734
04735
04736
04737
04738
04739
04740
04741
04742
04743
04744
04745 {
04746 ULONG NewTimeRemaining ;
04747
PRTLP_GENERIC_TIMER Temp ;
04748
04749
04750
04751
if (
RtlpRemoveFromDeltaList (DeltaList, Timer, TimeRemaining, NewFiringTime)) {
04752
04753
04754
04755 NewTimeRemaining = *NewFiringTime ;
04756
04757
04758 }
else {
04759
04760
04761
04762 NewTimeRemaining = TimeRemaining ;
04763
04764 }
04765
04766
04767
04768 Timer->
DeltaFiringTime = ChangedFiringTime ;
04769
04770
04771
04772
if (!
RtlpInsertInDeltaList (DeltaList, Timer, NewTimeRemaining, NewFiringTime)) {
04773
04774
04775
04776
04777
04778 *NewFiringTime = NewTimeRemaining ;
04779
04780
return (NewTimeRemaining != TimeRemaining) ;
04781
04782 }
else {
04783
04784
04785
04786
return TRUE ;
04787
04788 }
04789
04790 }
04791
04792
04793
VOID
04794 RtlpAddTimerQueue (
04795 PVOID Queue
04796 )
04797
04798
04799
04800
04801
04802
04803
04804
04805
04806
04807
04808
04809
04810
04811
04812 {
04813
04814
04815
04816
04817 }
04818
04819
04820
VOID
04821 RtlpServiceTimer (
04822 PVOID NotUsedArg,
04823 ULONG NotUsedLowTimer,
04824 LONG NotUsedHighTimer
04825 )
04826
04827
04828
04829
04830
04831
04832
04833
04834
04835
04836
04837
04838
04839
04840
04841
04842
04843
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
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
04883
04884
04885
04886
04887
04888
04889
04890
04891
04892
04893
for (QNode =
TimerQueues.Flink ; QNode != &
TimerQueues ; QNode = QNode->Flink) {
04894
04895 Queue = CONTAINING_RECORD (QNode,
RTLP_TIMER_QUEUE,
List) ;
04896
04897
04898
04899
04900
04901
if (Queue->DeltaFiringTime == 0) {
04902
04903
04904
04905
04906
RtlpFireTimersAndReorder (Queue, &NewFiringTime, &TimersToFireList) ;
04907
04908
04909
04910 QNode = QNode->Blink ;
04911
04912 RemoveEntryList (QNode->Flink) ;
04913
04914
04915
04916
04917
if (NewFiringTime !=
INFINITE_TIME) {
04918
04919 Queue->DeltaFiringTime = NewFiringTime ;
04920
04921
04922
04923
04924 InsertHeadList (&ReinsertTimerQueueList, &Queue->List) ;
04925
04926 }
else {
04927
04928
04929
04930 InitializeListHead (&Queue->List) ;
04931
04932 }
04933
04934
04935 }
else {
04936
04937
04938
04939
break ;
04940
04941 }
04942
04943 }
04944
04945
04946
04947
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
04960
04961
RtlpInsertTimersIntoDeltaList (&ReinsertTimerQueueList, &
TimerQueues,
04962 NewFiringTime, &NewFiringTime) ;
04963
04964 }
04965
04966
04967
04968 }
else {
04969
04970
if (!IsListEmpty (&ReinsertTimerQueueList)) {
04971
04972
04973
04974
RtlpInsertTimersIntoDeltaList (&ReinsertTimerQueueList, &
TimerQueues, 0,
04975 &NewFiringTime) ;
04976
04977 }
else {
04978
04979 NewFiringTime =
INFINITE_TIME ;
04980
04981 }
04982
04983
04984
04985 }
04986
04987
04988
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
05001
05002
RtlpFireTimers( &TimersToFireList ) ;
05003
05004
RELEASE_GLOBAL_TIMER_LOCK();
05005
05006 }
05007
05008
05009
VOID
05010 RtlpFireTimersAndReorder (
05011 PRTLP_TIMER_QUEUE Queue,
05012 ULONG *NewFiringTime,
05013 PLIST_ENTRY TimersToFireList
05014 )
05015
05016
05017
05018
05019
05020
05021
05022
05023
05024
05025
05026
05027
05028
05029
05030
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
05051
05052
if (Timer->DeltaFiringTime == 0) {
05053
05054
05055
05056 RemoveEntryList (TNode) ;
05057
05058
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
05077
05078
05079
if (Timer->Period == 0) {
05080
05081 InsertHeadList( &Queue->UncancelledTimerList, &Timer->List ) ;
05082
05083
05084
05085
if ( Timer->Wait ) {
05086
05087
05088
05089
05090
05091
05092
RtlpDeactivateWait( Timer->Wait ) ;
05093 }
05094
05095
else {
05096
05097
05098 Timer->State &= ~
STATE_ACTIVE ;
05099 }
05100
05101 Timer->State |=
STATE_ONE_SHOT_FIRED ;
05102
05103 }
else {
05104
05105
05106
05107 Timer->DeltaFiringTime = Timer->Period ;
05108
05109
05110
05111
RtlpInsertInDeltaList (TimerList, Timer, *NewFiringTime, NewFiringTime) ;
05112 }
05113
05114
05115
05116
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
05132
05133
break ;
05134
05135 }
05136 }
05137
05138
05139
if ( *NewFiringTime == 0 ) {
05140 *NewFiringTime =
INFINITE_TIME ;
05141 }
05142 }
05143
05144
05145
VOID
05146 RtlpInsertTimersIntoDeltaList (
05147 IN PLIST_ENTRY NewTimerList,
05148 IN PLIST_ENTRY DeltaTimerList,
05149 IN ULONG TimeRemaining,
05150 OUT ULONG *NewFiringTime
05151 )
05152
05153
05154
05155
05156
05157
05158
05159
05160
05161
05162
05163
05164
05165
05166
05167
05168
05169
05170
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 }
05198
05199
05200 LONG
05201 RtlpTimerThread (
05202 PVOID Initialized
05203 )
05204
05205
05206
05207
05208
05209
05210
05211
05212
05213
05214
05215
05216
05217
05218 {
05219 LARGE_INTEGER TimeOut ;
05220
05221
05222
05223
05224
05225
TimerThreadId = HandleToUlong(NtCurrentTeb()->ClientId.UniqueThread) ;
05226
05227
05228
05229
05230
RtlpResetTimer (
TimerHandle, -1,
NULL) ;
05231
05232
05233
05234 InterlockedExchange ((ULONG *)
Initialized, 1) ;
05235
05236
05237
05238
05239
for ( ; ; ) {
05240
05241
05242
05243 TimeOut.LowPart = 0 ;
05244 TimeOut.HighPart = 0x80000000 ;
05245
05246
NtDelayExecution (
TRUE, &TimeOut) ;
05247
05248 }
05249
05250
return 0 ;
05251
05252 }
05253
05254
05255
NTSTATUS
05256 RtlpInitializeTimerThreadPool (
05257 )
05258
05259
05260
05261
05262
05263
05264
05265
05266
05267
05268
05269
05270 {
05271
NTSTATUS Status = STATUS_SUCCESS;
05272 LARGE_INTEGER TimeOut ;
05273
05274
05275
05276
05277
05278
05279
05280
if (!InterlockedExchange(&
StartedTimerInitialization, 1
L)) {
05281
05282
if (
CompletedTimerInitialization)
05283 InterlockedExchange(&
CompletedTimerInitialization, 0 ) ;
05284
05285
do {
05286
05287
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) ;
05305
05306
05307
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, 1
L) ;
05332
05333 }
else {
05334
05335
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 }
05351
05352
05353
NTSTATUS
05354 RtlpDeleteTimerQueue (
05355 PRTLP_TIMER_QUEUE Queue
05356 )
05357
05358
05359
05360
05361
05362
05363
05364
05365
05366
05367
05368
05369
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
05384
05385
05386
05387
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
05399
05400
RtlpResetTimer (
TimerHandle, NewFiringTime,
NULL) ;
05401 }
05402
05403
05404
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 ) ;
05413 }
05414 }
05415
05416
05417
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 ) ;
05426 }
05427
05428
05429
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 }
05443
05444
05445
05446
05447
05448
05449
05450
05451
05452
05453
05454
05455
05456
05457
05458
05459
05460
05461
VOID
05462 RtlpDeleteTimerQueueComplete (
05463 PRTLP_TIMER_QUEUE Queue
05464 )
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
05475
05476
if ( Queue->CompletionEvent )
05477
NtSetEvent (Queue->CompletionEvent,
NULL) ;
05478
05479
RtlpFreeTPHeap( Queue ) ;
05480 }
05481
05482
05483
VOID
05484 RtlpThreadCleanup (
05485 )
05486
05487
05488
05489
05490
05491
05492
05493
05494
05495
05496
05497 {
05498
NtTerminateThread( NtCurrentThread(), 0) ;
05499 }
05500
05501
05502
NTSTATUS
05503 RtlpWaitForEvent (
05504 HANDLE Event,
05505 HANDLE ThreadHandle
05506 )
05507
05508
05509
05510
05511
05512
05513
05514
05515
05516
05517
05518
05519
05520
05521
05522
05523
05524
05525
05526 {
05527
NTSTATUS Status ;
05528 LARGE_INTEGER TimeOut ;
05529
05530
05531
ONE_SECOND_TIMEOUT(TimeOut) ;
05532
05533 Wait:
05534
05535
Status =
NtWaitForSingleObject (
Event,
FALSE, &TimeOut) ;
05536
05537
if (
Status == STATUS_TIMEOUT) {
05538
05539
05540
05541
05542
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
05555
05556
goto Wait ;
05557
05558 }
else {
05559
05560
05561
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 }
05572
05573
05574
PRTLP_EVENT
05575 RtlpGetWaitEvent (
05576 VOID
05577 )
05578
05579
05580
05581
05582
05583
05584
05585
05586
05587
05588
05589
05590
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 }
05645
05646
05647
VOID
05648 RtlpFreeWaitEvent (
05649
PRTLP_EVENT Event
05650 )
05651
05652
05653
05654
05655
05656
05657
05658
05659
05660
05661
05662
05663
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 }
05690
05691
05692
05693
VOID
05694 RtlpInitializeEventCache (
05695 VOID
05696 )
05697
05698
05699
05700
05701
05702
05703
05704
05705
05706
05707
05708
05709
05710
05711
05712 {
05713
NTSTATUS Status;
05714 LARGE_INTEGER TimeOut ;
05715
05716
if (!InterlockedExchange(&
StartedEventCacheInitialization, 1
L)) {
05717
05718 InitializeListHead (&
EventCache) ;
05719
05720
Status =
RtlInitializeCriticalSection(&
EventCacheCriticalSection) ;
05721
05722
ASSERT (
Status == STATUS_SUCCESS) ;
05723
05724
NumUnusedEvents = 0 ;
05725
05726 InterlockedExchange (&
CompletedEventCacheInitialization, 1
L) ;
05727
05728 }
else {
05729
05730
05731
05732
ONE_MILLISECOND_TIMEOUT(TimeOut) ;
05733
05734
while (!(
volatile ULONG)
CompletedEventCacheInitialization) {
05735
05736
NtDelayExecution (
FALSE, &TimeOut) ;
05737
05738 }
05739
05740 }
05741 }
05742
05743
05744
VOID
05745 PrintTimerQueue(PLIST_ENTRY QNode, ULONG Delta, ULONG Count
05746 )
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 }
05765
05766
VOID
05767 RtlDebugPrintTimes (
05768 )
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 }
05813
05814
05815
05816
05817
NTSTATUS
05818 RtlSetTimer(
05819 IN HANDLE TimerQueueHandle,
05820 OUT HANDLE *Handle,
05821 IN WAITORTIMERCALLBACKFUNC Function,
05822 IN PVOID Context,
05823 IN ULONG DueTime,
05824 IN ULONG Period,
05825 IN ULONG Flags
05826 )
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 }
05844
05845
05846 PVOID
05847 RtlpForceAllocateTPHeap(
05848 ULONG dwSize,
05849 ULONG dwFlags
05850 )
05851
05852
05853
05854
05855
05856
05857
05858
05859
05860
05861
05862
05863
05864
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 }
05889
05890
05891
05892
05893
05894
NTSTATUS
05895 RtlCancelTimer(
05896 IN HANDLE TimerQueueHandle,
05897 IN HANDLE TimerToCancel
05898 )
05899
05900
05901
05902
05903
05904
05905
05906
05907
05908
05909
05910
05911
05912
05913
05914
05915
05916
05917
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 }
05930