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
00079
00080
00081 Thread =
KeGetCurrentThread();
00082
KiLockApcQueue(Thread, &OldIrql);
00083
00084
00085
00086
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
00102
00103
00104
00105
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
00132
00133
00134
00135
00136
00137
00138
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
00181
00182
00183
00184
00185
00186
00187
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 }