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

apcsup.c File Reference

#include "ki.h"

Go to the source code of this file.

Functions

VOID KiDeliverApc (IN KPROCESSOR_MODE PreviousMode, IN PKEXCEPTION_FRAME ExceptionFrame, IN PKTRAP_FRAME TrapFrame)
BOOLEAN FASTCALL KiInsertQueueApc (IN PKAPC Apc, IN KPRIORITY Increment)


Function Documentation

VOID KiDeliverApc IN KPROCESSOR_MODE  PreviousMode,
IN PKEXCEPTION_FRAME  ExceptionFrame,
IN PKTRAP_FRAME  TrapFrame
 

Definition at line 30 of file apcsup.c.

References APC_LEVEL, _KAPC_STATE::ApcListHead, _KTHREAD::ApcState, FALSE, _KAPC::Inserted, KeBugCheckEx(), KeGetCurrentThread, KeLowerIrql(), KeRaiseIrql(), _KTHREAD::KernelApcDisable, _KAPC_STATE::KernelApcInProgress, _KAPC_STATE::KernelApcPending, KernelMode, _KAPC::KernelRoutine, KeTestAlertThread(), KiInitializeUserApc(), KiLockApcQueue, KiUnlockApcQueue, _KAPC::NormalContext, _KAPC::NormalRoutine, NULL, PKKERNEL_ROUTINE, PKNORMAL_ROUTINE, _KAPC::SystemArgument1, _KAPC::SystemArgument2, TRUE, _KAPC_STATE::UserApcPending, and UserMode.

Referenced by KiDispatchSoftwareInterrupt().

00038 : 00039 00040 This function is called from the APC interrupt code and when one or 00041 more of the APC pending flags are set at system exit and the previous 00042 IRQL is zero. All special kernel APC's are delivered first, followed 00043 by normal kernel APC's if one is not already in progress, and finally 00044 if the user APC queue is not empty, the user APC pending flag is set, 00045 and the previous mode is user, then a user APC is delivered. On entry 00046 to this routine IRQL is set to APC_LEVEL. 00047 00048 N.B. The exception frame and trap frame addresses are only guaranteed 00049 to be valid if, and only if, the previous mode is user. 00050 00051 Arguments: 00052 00053 PreviousMode - Supplies the previous processor mode. 00054 00055 ExceptionFrame - Supplies a pointer to an exception frame. 00056 00057 TrapFrame - Supplies a pointer to a trap frame. 00058 00059 Return Value: 00060 00061 None. 00062 00063 --*/ 00064 00065 { 00066 00067 PKAPC Apc; 00068 PKKERNEL_ROUTINE KernelRoutine; 00069 PLIST_ENTRY NextEntry; 00070 PVOID NormalContext; 00071 PKNORMAL_ROUTINE NormalRoutine; 00072 KIRQL OldIrql; 00073 PVOID SystemArgument1; 00074 PVOID SystemArgument2; 00075 PKTHREAD Thread; 00076 00077 // 00078 // Raise IRQL to dispatcher level and lock the APC queue. 00079 // 00080 00081 Thread = KeGetCurrentThread(); 00082 KiLockApcQueue(Thread, &OldIrql); 00083 00084 // 00085 // Get address of current thread object, clear kernel APC pending, and 00086 // check if any kernel mode APC's can be delivered. 00087 // 00088 00089 Thread->ApcState.KernelApcPending = FALSE; 00090 while (IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode]) == FALSE) { 00091 NextEntry = Thread->ApcState.ApcListHead[KernelMode].Flink; 00092 Apc = CONTAINING_RECORD(NextEntry, KAPC, ApcListEntry); 00093 KernelRoutine = Apc->KernelRoutine; 00094 NormalRoutine = Apc->NormalRoutine; 00095 NormalContext = Apc->NormalContext; 00096 SystemArgument1 = Apc->SystemArgument1; 00097 SystemArgument2 = Apc->SystemArgument2; 00098 if (NormalRoutine == (PKNORMAL_ROUTINE)NULL) { 00099 00100 // 00101 // First entry in the kernel APC queue is a special kernel APC. 00102 // Remove the entry from the APC queue, set its inserted state 00103 // to FALSE, release dispatcher database lock, and call the kernel 00104 // routine. On return raise IRQL to dispatcher level and lock 00105 // dispatcher database lock. 00106 // 00107 00108 RemoveEntryList(NextEntry); 00109 Apc->Inserted = FALSE; 00110 KiUnlockApcQueue(Thread, OldIrql); 00111 (KernelRoutine)(Apc, &NormalRoutine, &NormalContext, 00112 &SystemArgument1, &SystemArgument2); 00113 00114 #if DBG 00115 00116 if (KeGetCurrentIrql() != OldIrql) { 00117 KeBugCheckEx(IRQL_UNEXPECTED_VALUE, 00118 KeGetCurrentIrql() << 16 | OldIrql << 8, 00119 (ULONG_PTR)KernelRoutine, 00120 (ULONG_PTR)Apc, 00121 (ULONG_PTR)NormalRoutine); 00122 } 00123 00124 #endif 00125 00126 KiLockApcQueue(Thread, &OldIrql); 00127 00128 } else { 00129 00130 // 00131 // First entry in the kernel APC queue is a normal kernel APC. 00132 // If there is not a normal kernel APC in progress and kernel 00133 // APC's are not disabled, then remove the entry from the APC 00134 // queue, set its inserted state to FALSE, release the APC queue 00135 // lock, call the specified kernel routine, set kernel APC in 00136 // progress, lower the IRQL to zero, and call the normal kernel 00137 // APC routine. On return raise IRQL to dispatcher level, lock 00138 // the APC queue, and clear kernel APC in progress. 00139 // 00140 00141 if ((Thread->ApcState.KernelApcInProgress == FALSE) && 00142 (Thread->KernelApcDisable == 0)) { 00143 RemoveEntryList(NextEntry); 00144 Apc->Inserted = FALSE; 00145 KiUnlockApcQueue(Thread, OldIrql); 00146 (KernelRoutine)(Apc, &NormalRoutine, &NormalContext, 00147 &SystemArgument1, &SystemArgument2); 00148 00149 #if DBG 00150 00151 if (KeGetCurrentIrql() != OldIrql) { 00152 KeBugCheckEx(IRQL_UNEXPECTED_VALUE, 00153 KeGetCurrentIrql() << 16 | OldIrql << 8 | 1, 00154 (ULONG_PTR)KernelRoutine, 00155 (ULONG_PTR)Apc, 00156 (ULONG_PTR)NormalRoutine); 00157 } 00158 00159 #endif 00160 00161 if (NormalRoutine != (PKNORMAL_ROUTINE)NULL) { 00162 Thread->ApcState.KernelApcInProgress = TRUE; 00163 KeLowerIrql(0); 00164 (NormalRoutine)(NormalContext, SystemArgument1, 00165 SystemArgument2); 00166 KeRaiseIrql(APC_LEVEL, &OldIrql); 00167 } 00168 00169 KiLockApcQueue(Thread, &OldIrql); 00170 Thread->ApcState.KernelApcInProgress = FALSE; 00171 00172 } else { 00173 KiUnlockApcQueue(Thread, OldIrql); 00174 return; 00175 } 00176 } 00177 } 00178 00179 // 00180 // Kernel APC queue is empty. If the previous mode is user, user APC 00181 // pending is set, and the user APC queue is not empty, then remove 00182 // the first entry from the user APC queue, set its inserted state to 00183 // FALSE, clear user APC pending, release the dispatcher database lock, 00184 // and call the specified kernel routine. If the normal routine address 00185 // is not NULL on return from the kernel routine, then initialize the 00186 // user mode APC context and return. Otherwise, check to determine if 00187 // another user mode APC can be processed. 00188 // 00189 00190 if ((IsListEmpty(&Thread->ApcState.ApcListHead[UserMode]) == FALSE) && 00191 (PreviousMode == UserMode) && (Thread->ApcState.UserApcPending == TRUE)) { 00192 Thread->ApcState.UserApcPending = FALSE; 00193 NextEntry = Thread->ApcState.ApcListHead[UserMode].Flink; 00194 Apc = CONTAINING_RECORD(NextEntry, KAPC, ApcListEntry); 00195 KernelRoutine = Apc->KernelRoutine; 00196 NormalRoutine = Apc->NormalRoutine; 00197 NormalContext = Apc->NormalContext; 00198 SystemArgument1 = Apc->SystemArgument1; 00199 SystemArgument2 = Apc->SystemArgument2; 00200 RemoveEntryList(NextEntry); 00201 Apc->Inserted = FALSE; 00202 KiUnlockApcQueue(Thread, OldIrql); 00203 (KernelRoutine)(Apc, &NormalRoutine, &NormalContext, 00204 &SystemArgument1, &SystemArgument2); 00205 00206 if (NormalRoutine == (PKNORMAL_ROUTINE)NULL) { 00207 KeTestAlertThread(UserMode); 00208 00209 } else { 00210 KiInitializeUserApc(ExceptionFrame, TrapFrame, NormalRoutine, 00211 NormalContext, SystemArgument1, SystemArgument2); 00212 } 00213 00214 } else { 00215 KiUnlockApcQueue(Thread, OldIrql); 00216 } 00217 00218 return; 00219 }

BOOLEAN FASTCALL KiInsertQueueApc IN PKAPC  Apc,
IN KPRIORITY  Increment
 

Definition at line 223 of file apcsup.c.

References _KTHREAD::Alertable, _KAPC_STATE::ApcListHead, _KTHREAD::ApcQueueLock, _KTHREAD::ApcState, _KTHREAD::ApcStateIndex, _KTHREAD::ApcStatePointer, FALSE, Increment, _KTHREAD::KernelApcDisable, _KAPC_STATE::KernelApcInProgress, _KAPC_STATE::KernelApcPending, KernelMode, KiRequestApcInterrupt, KiUnwaitThread(), KPROCESSOR_MODE, _KTHREAD::NextProcessor, _KAPC::NormalRoutine, NULL, PsExitSpecialApc(), Running, _KTHREAD::State, TRUE, _KAPC_STATE::UserApcPending, UserMode, Waiting, _KTHREAD::WaitIrql, and _KTHREAD::WaitMode.

Referenced by Ke386VdmInsertQueueApc(), KeFreezeAllThreads(), KeInsertQueueApc(), and KeSuspendThread().

00230 : 00231 00232 This function inserts an APC object into a thread's APC queue. The address 00233 of the thread object, the APC queue, and the type of APC are all derived 00234 from the APC object. If the APC object is already in an APC queue, then 00235 no opertion is performed and a function value of FALSE is returned. Else 00236 the APC is inserted in the specified APC queue, its inserted state is set 00237 to TRUE, and a function value of TRUE is returned. The APC will actually 00238 be delivered when proper enabling conditions exist. 00239 00240 Arguments: 00241 00242 Apc - Supplies a pointer to a control object of type APC. 00243 00244 Increment - Supplies the priority increment that is to be applied if 00245 queuing the APC causes a thread wait to be satisfied. 00246 00247 Return Value: 00248 00249 If the APC object is already in an APC queue, then a value of FALSE is 00250 returned. Else a value of TRUE is returned. 00251 00252 --*/ 00253 00254 { 00255 00256 KPROCESSOR_MODE ApcMode; 00257 PKAPC ApcEntry; 00258 PKAPC_STATE ApcState; 00259 BOOLEAN Inserted; 00260 PLIST_ENTRY ListEntry; 00261 PKTHREAD Thread; 00262 00263 // 00264 // If the APC object is already in an APC queue, then set inserted to 00265 // FALSE. Else insert the APC object in the proper queue, set the APC 00266 // inserted state to TRUE, check to determine if the APC should be delivered 00267 // immediately, and set inserted to TRUE. 00268 // 00269 // For multiprocessor performance, the following code utilizes the fact 00270 // that kernel APC disable count is incremented before checking whether 00271 // the kernel APC queue is nonempty. 00272 // 00273 // See KeLeaveCriticalRegion(). 00274 // 00275 00276 Thread = Apc->Thread; 00277 KiAcquireSpinLock(&Thread->ApcQueueLock); 00278 if (Apc->Inserted) { 00279 Inserted = FALSE; 00280 00281 } else { 00282 ApcState = Thread->ApcStatePointer[Apc->ApcStateIndex]; 00283 00284 // 00285 // Insert the APC after all other special APC entries selected by 00286 // the processor mode if the normal routine value is null. Else 00287 // insert the APC object at the tail of the APC queue selected by 00288 // the processor mode unless the APC mode is user and the address 00289 // of the special APC routine is exit thread, in which case insert 00290 // the APC at the front of the list and set user APC pending. 00291 // 00292 00293 ApcMode = Apc->ApcMode; 00294 if (Apc->NormalRoutine != NULL) { 00295 if ((ApcMode != KernelMode) && (Apc->KernelRoutine == PsExitSpecialApc)) { 00296 Thread->ApcState.UserApcPending = TRUE; 00297 InsertHeadList(&ApcState->ApcListHead[ApcMode], 00298 &Apc->ApcListEntry); 00299 00300 } else { 00301 InsertTailList(&ApcState->ApcListHead[ApcMode], 00302 &Apc->ApcListEntry); 00303 } 00304 00305 } else { 00306 ListEntry = ApcState->ApcListHead[ApcMode].Flink; 00307 while (ListEntry != &ApcState->ApcListHead[ApcMode]) { 00308 ApcEntry = CONTAINING_RECORD(ListEntry, KAPC, ApcListEntry); 00309 if (ApcEntry->NormalRoutine != NULL) { 00310 break; 00311 } 00312 00313 ListEntry = ListEntry->Flink; 00314 } 00315 00316 ListEntry = ListEntry->Blink; 00317 InsertHeadList(ListEntry, &Apc->ApcListEntry); 00318 } 00319 00320 Apc->Inserted = TRUE; 00321 00322 // 00323 // If the APC index from the APC object matches the APC Index of 00324 // the thread, then check to determine if the APC should interrupt 00325 // thread execution or sequence the thread out of a wait state. 00326 // 00327 00328 if (Apc->ApcStateIndex == Thread->ApcStateIndex) { 00329 00330 // 00331 // If the processor mode of the APC is kernel, then check if 00332 // the APC should either interrupt the thread or sequence the 00333 // thread out of a Waiting state. Else check if the APC should 00334 // sequence the thread out of an alertable Waiting state. 00335 // 00336 00337 if (ApcMode == KernelMode) { 00338 Thread->ApcState.KernelApcPending = TRUE; 00339 if (Thread->State == Running) { 00340 KiRequestApcInterrupt(Thread->NextProcessor); 00341 00342 } else if ((Thread->State == Waiting) && 00343 (Thread->WaitIrql == 0) && 00344 ((Apc->NormalRoutine == NULL) || 00345 ((Thread->KernelApcDisable == 0) && 00346 (Thread->ApcState.KernelApcInProgress == FALSE)))) { 00347 KiUnwaitThread(Thread, STATUS_KERNEL_APC, Increment); 00348 } 00349 00350 } else if ((Thread->State == Waiting) && 00351 (Thread->WaitMode == UserMode) && 00352 (Thread->Alertable)) { 00353 Thread->ApcState.UserApcPending = TRUE; 00354 KiUnwaitThread(Thread, STATUS_USER_APC, Increment); 00355 } 00356 } 00357 00358 Inserted = TRUE; 00359 } 00360 00361 // 00362 // Unlock the APC queue lock, and return whether the APC object was 00363 // inserted in an APC queue. 00364 // 00365 00366 KiReleaseSpinLock(&Thread->ApcQueueLock); 00367 return Inserted; 00368 } }


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