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

waitsup.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1989 Microsoft Corporation 00004 00005 Module Name: 00006 00007 waitsup.c 00008 00009 Abstract: 00010 00011 This module contains the support routines necessary to support the 00012 generic kernel wait functions. Functions are provided to test if a 00013 wait can be satisfied, to satisfy a wait, and to unwwait a thread. 00014 00015 Author: 00016 00017 David N. Cutler (davec) 24-Mar-1989 00018 00019 Environment: 00020 00021 Kernel mode only. 00022 00023 Revision History: 00024 00025 --*/ 00026 00027 #include "ki.h" 00028 00029 VOID 00030 FASTCALL 00031 KiUnwaitThread ( 00032 IN PRKTHREAD Thread, 00033 IN LONG_PTR WaitStatus, 00034 IN KPRIORITY Increment 00035 ) 00036 00037 /*++ 00038 00039 Routine Description: 00040 00041 This function unwaits a thread, sets the thread's wait completion status, 00042 calculates the thread's new priority, and readies the thread for execution. 00043 00044 Arguments: 00045 00046 Thread - Supplies a pointer to a dispatcher object of type thread. 00047 00048 WaitStatus - Supplies the wait completion status. 00049 00050 Increment - Supplies the priority increment that is to be applied to 00051 the thread's priority. 00052 00053 Return Value: 00054 00055 None. 00056 00057 --*/ 00058 00059 { 00060 00061 KPRIORITY NewPriority; 00062 PKPROCESS Process; 00063 PKQUEUE Queue; 00064 PKTIMER Timer; 00065 PRKWAIT_BLOCK WaitBlock; 00066 00067 // 00068 // Set wait completion status, remove wait blocks from object wait 00069 // lists, and remove thread from wait list. 00070 // 00071 00072 Thread->WaitStatus |= WaitStatus; 00073 WaitBlock = Thread->WaitBlockList; 00074 do { 00075 RemoveEntryList(&WaitBlock->WaitListEntry); 00076 WaitBlock = WaitBlock->NextWaitBlock; 00077 } while (WaitBlock != Thread->WaitBlockList); 00078 00079 RemoveEntryList(&Thread->WaitListEntry); 00080 00081 // 00082 // If thread timer is still active, then cancel thread timer. 00083 // 00084 00085 Timer = &Thread->Timer; 00086 if (Timer->Header.Inserted != FALSE) { 00087 KiRemoveTreeTimer(Timer); 00088 } 00089 00090 // 00091 // If the thread is processing a queue entry, then increment the 00092 // count of currently active threads. 00093 // 00094 00095 Queue = Thread->Queue; 00096 if (Queue != NULL) { 00097 Queue->CurrentCount += 1; 00098 } 00099 00100 // 00101 // If the thread runs at a realtime priority level, then reset the 00102 // thread quantum. Otherwise, compute the next thread priority and 00103 // charge the thread for the wait operation. 00104 // 00105 00106 Process = Thread->ApcState.Process; 00107 if (Thread->Priority < LOW_REALTIME_PRIORITY) { 00108 if ((Thread->PriorityDecrement == 0) && 00109 (Thread->DisableBoost == FALSE)) { 00110 NewPriority = Thread->BasePriority + Increment; 00111 if (((PEPROCESS)Process)->Vm.MemoryPriority == MEMORY_PRIORITY_FOREGROUND) { 00112 NewPriority += PsPrioritySeperation; 00113 } 00114 00115 if (NewPriority > Thread->Priority) { 00116 if (NewPriority >= LOW_REALTIME_PRIORITY) { 00117 Thread->Priority = LOW_REALTIME_PRIORITY - 1; 00118 00119 } else { 00120 Thread->Priority = (SCHAR)NewPriority; 00121 } 00122 } 00123 } 00124 00125 if (Thread->BasePriority >= TIME_CRITICAL_PRIORITY_BOUND) { 00126 Thread->Quantum = Process->ThreadQuantum; 00127 00128 } else { 00129 Thread->Quantum -= WAIT_QUANTUM_DECREMENT; 00130 if (Thread->Quantum <= 0) { 00131 Thread->Quantum = Process->ThreadQuantum; 00132 Thread->Priority -= (Thread->PriorityDecrement + 1); 00133 if (Thread->Priority < Thread->BasePriority) { 00134 Thread->Priority = Thread->BasePriority; 00135 } 00136 00137 Thread->PriorityDecrement = 0; 00138 } 00139 } 00140 00141 } else { 00142 Thread->Quantum = Process->ThreadQuantum; 00143 } 00144 00145 // 00146 // Reready the thread for execution. 00147 // 00148 00149 KiReadyThread(Thread); 00150 return; 00151 } 00152 00153 VOID 00154 KeBoostCurrentThread( 00155 VOID 00156 ) 00157 00158 /*++ 00159 00160 Routine Description: 00161 00162 This function boosts the priority of the current thread for one quantum, 00163 then reduce the thread priority to the base priority of the thread. 00164 00165 Arguments: 00166 00167 None. 00168 00169 Return Value: 00170 00171 None. 00172 00173 --*/ 00174 00175 { 00176 00177 KIRQL OldIrql; 00178 PKTHREAD Thread; 00179 00180 // 00181 // Get current thread address, raise IRQL to synchronization level, and 00182 // lock the dispatcher database 00183 // 00184 00185 Thread = KeGetCurrentThread(); 00186 00187 redoboost: 00188 KiLockDispatcherDatabase(&OldIrql); 00189 00190 // 00191 // If a priority boost is not already active for the current thread 00192 // and the thread priority is less than 14, then boost the thread 00193 // priority to 14 and give the thread a large quantum. Otherwise, 00194 // if a priority boost is active, then decrement the round trip 00195 // count. If the count goes to zero, then release the dispatcher 00196 // database lock, lower the thread priority to the base priority, 00197 // and then attempt to boost the priority again. This will give 00198 // other threads a chance to run. If the count does not reach zero, 00199 // then give the thread another large qunatum. 00200 // 00201 // If the thread priority is above 14, then no boost is applied. 00202 // 00203 00204 if ((Thread->PriorityDecrement == 0) && (Thread->Priority < 14)) { 00205 Thread->PriorityDecrement = 14 - Thread->BasePriority; 00206 Thread->DecrementCount = ROUND_TRIP_DECREMENT_COUNT; 00207 Thread->Priority = 14; 00208 Thread->Quantum = Thread->ApcState.Process->ThreadQuantum * 2; 00209 00210 } else if (Thread->PriorityDecrement != 0) { 00211 Thread->DecrementCount -= 1; 00212 if (Thread->DecrementCount == 0) { 00213 KiUnlockDispatcherDatabase(OldIrql); 00214 KeSetPriorityThread(Thread, Thread->BasePriority); 00215 goto redoboost; 00216 00217 } else { 00218 Thread->Quantum = Thread->ApcState.Process->ThreadQuantum * 2; 00219 } 00220 } 00221 00222 KiUnlockDispatcherDatabase(OldIrql); 00223 return; 00224 } 00225 00226 VOID 00227 FASTCALL 00228 KiWaitSatisfyAll ( 00229 IN PRKWAIT_BLOCK WaitBlock 00230 ) 00231 00232 /*++ 00233 00234 Routine Description: 00235 00236 This function satisfies a wait all and performs any side effects that 00237 are necessary. 00238 00239 Arguments: 00240 00241 WaitBlock - Supplies a pointer to a wait block. 00242 00243 Return Value: 00244 00245 None. 00246 00247 --*/ 00248 00249 { 00250 00251 PKMUTANT Object; 00252 PRKTHREAD Thread; 00253 PRKWAIT_BLOCK WaitBlock1; 00254 00255 // 00256 // If the wait type was WaitAny, then perform neccessary side effects on 00257 // the object specified by the wait block. Else perform necessary side 00258 // effects on all the objects that were involved in the wait operation. 00259 // 00260 00261 WaitBlock1 = WaitBlock; 00262 Thread = WaitBlock1->Thread; 00263 do { 00264 if (WaitBlock1->WaitKey != (CSHORT)STATUS_TIMEOUT) { 00265 Object = (PKMUTANT)WaitBlock1->Object; 00266 KiWaitSatisfyAny(Object, Thread); 00267 } 00268 00269 WaitBlock1 = WaitBlock1->NextWaitBlock; 00270 } while (WaitBlock1 != WaitBlock); 00271 00272 return; 00273 } 00274 00275 VOID 00276 FASTCALL 00277 KiWaitTest ( 00278 IN PVOID Object, 00279 IN KPRIORITY Increment 00280 ) 00281 00282 /*++ 00283 00284 Routine Description: 00285 00286 This function tests if a wait can be satisfied when an object attains 00287 a state of signaled. If a wait can be satisfied, then the subject thread 00288 is unwaited with a completion status that is the WaitKey of the wait 00289 block from the object wait list. As many waits as possible are satisfied. 00290 00291 Arguments: 00292 00293 Object - Supplies a pointer to a dispatcher object. 00294 00295 Return Value: 00296 00297 None. 00298 00299 --*/ 00300 00301 { 00302 00303 PKEVENT Event; 00304 PLIST_ENTRY ListHead; 00305 PRKWAIT_BLOCK NextBlock; 00306 PKMUTANT Mutant; 00307 PRKTHREAD Thread; 00308 PRKWAIT_BLOCK WaitBlock; 00309 PLIST_ENTRY WaitEntry; 00310 00311 // 00312 // As long as the signal state of the specified object is Signaled and 00313 // there are waiters in the object wait list, then try to satisfy a wait. 00314 // 00315 00316 Event = (PKEVENT)Object; 00317 ListHead = &Event->Header.WaitListHead; 00318 WaitEntry = ListHead->Flink; 00319 while ((Event->Header.SignalState > 0) && 00320 (WaitEntry != ListHead)) { 00321 WaitBlock = CONTAINING_RECORD(WaitEntry, KWAIT_BLOCK, WaitListEntry); 00322 Thread = WaitBlock->Thread; 00323 if (WaitBlock->WaitType != WaitAny) { 00324 00325 // 00326 // The wait type is wait all - if all the objects are in 00327 // a Signaled state, then satisfy the wait. 00328 // 00329 00330 NextBlock = WaitBlock->NextWaitBlock; 00331 while (NextBlock != WaitBlock) { 00332 if (NextBlock->WaitKey != (CSHORT)(STATUS_TIMEOUT)) { 00333 Mutant = (PKMUTANT)NextBlock->Object; 00334 if ((Mutant->Header.Type == MutantObject) && 00335 (Mutant->Header.SignalState <= 0) && 00336 (Thread == Mutant->OwnerThread)) { 00337 goto next; 00338 00339 } else if (Mutant->Header.SignalState <= 0) { 00340 goto scan; 00341 } 00342 } 00343 00344 next: 00345 NextBlock = NextBlock->NextWaitBlock; 00346 } 00347 00348 // 00349 // All objects associated with the wait are in the Signaled 00350 // state - satisfy the wait. 00351 // 00352 00353 WaitEntry = WaitEntry->Blink; 00354 KiWaitSatisfyAll(WaitBlock); 00355 00356 } else { 00357 00358 // 00359 // The wait type is wait any - satisfy the wait. 00360 // 00361 00362 WaitEntry = WaitEntry->Blink; 00363 KiWaitSatisfyAny((PKMUTANT)Event, Thread); 00364 } 00365 00366 KiUnwaitThread(Thread, (NTSTATUS)WaitBlock->WaitKey, Increment); 00367 00368 scan: 00369 WaitEntry = WaitEntry->Flink; 00370 } 00371 00372 return; 00373 } 00374 

Generated on Sat May 15 19:42:24 2004 for test by doxygen 1.3.7