diff --git a/reactos/bootdata/packages/reactos.dff b/reactos/bootdata/packages/reactos.dff index 732d8d0dd3f..3755eb0eaa8 100755 --- a/reactos/bootdata/packages/reactos.dff +++ b/reactos/bootdata/packages/reactos.dff @@ -83,6 +83,8 @@ lib\kbduk\kbduk.dll 1 lib\kbdus\kbdus.dll 1 lib\kernel32\kernel32.dll 1 lib\lzexpand\lz32.dll 1 +lib\midimap\midimap.dll 1 +lib\mmdrv\mmdrv.dll 1 lib\mpr\mpr.dll 1 lib\msafd\msafd.dll 1 lib\msgina\msgina.dll 1 diff --git a/reactos/hal/halx86/irql.c b/reactos/hal/halx86/irql.c index 3ccc97028c3..12f9fe9c412 100644 --- a/reactos/hal/halx86/irql.c +++ b/reactos/hal/halx86/irql.c @@ -1,4 +1,4 @@ -/* $Id: irql.c,v 1.19 2004/11/01 14:37:19 hbirr Exp $ +/* $Id: irql.c,v 1.20 2004/11/10 02:50:59 ion Exp $ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel @@ -188,7 +188,7 @@ HalpLowerIrql(KIRQL NewIrql) if (KeGetCurrentThread() != NULL && KeGetCurrentThread()->ApcState.KernelApcPending) { - KiDeliverApc(0, 0, 0); + KiDeliverApc(KernelMode, NULL, NULL); } KeGetCurrentKPCR()->Irql = PASSIVE_LEVEL; } diff --git a/reactos/include/ddk/kefuncs.h b/reactos/include/ddk/kefuncs.h index 96486129abd..98c3fe105ff 100644 --- a/reactos/include/ddk/kefuncs.h +++ b/reactos/include/ddk/kefuncs.h @@ -530,10 +530,6 @@ KfReleaseSpinLock ( ); -VOID STDCALL KiDeliverApc(ULONG Unknown1, - ULONG Unknown2, - ULONG Unknown3); - VOID STDCALL KiDispatchInterrupt(VOID); /* Stubs Start here */ diff --git a/reactos/include/ddk/ketypes.h b/reactos/include/ddk/ketypes.h index d559ff5da2d..c50b501fdda 100644 --- a/reactos/include/ddk/ketypes.h +++ b/reactos/include/ddk/ketypes.h @@ -36,7 +36,23 @@ typedef VOID STDCALL_FUNC struct _DISPATCHER_HEADER; - +typedef enum _KERNEL_OBJECTS { + KNotificationEvent = 0, + KSynchronizationEvent = 1, + KMutant = 2, + KProcess = 3, + KQueue = 4, + KSemaphore = 5, + KThread = 6, + KNotificationTimer = 8, + KSynchronizationTimer = 9, + KApc = 18, + KDpc = 19, + KDeviceQueue = 20, + KEventPair = 21, + KInterrupt = 22, + KProfile = 23 +} KERNEL_OBJECTS; #include @@ -84,7 +100,7 @@ typedef struct _KDEVICE_QUEUE } KDEVICE_QUEUE, *PKDEVICE_QUEUE; -#include +#include typedef struct _KAPC { @@ -101,7 +117,7 @@ typedef struct _KAPC PVOID SystemArgument2; CCHAR ApcStateIndex; KPROCESSOR_MODE ApcMode; - USHORT Inserted; + BOOLEAN Inserted; } KAPC, *PKAPC; #include diff --git a/reactos/ntoskrnl/include/internal/ke.h b/reactos/ntoskrnl/include/internal/ke.h index 800025d306e..99b68718ce3 100644 --- a/reactos/ntoskrnl/include/internal/ke.h +++ b/reactos/ntoskrnl/include/internal/ke.h @@ -85,8 +85,20 @@ BOOLEAN KiTestAlert(VOID); VOID KeRemoveAllWaitsThread(struct _ETHREAD* Thread, NTSTATUS WaitStatus, BOOL Unblock); PULONG KeGetStackTopThread(struct _ETHREAD* Thread); VOID KeContextToTrapFrame(PCONTEXT Context, PKTRAP_FRAME TrapFrame); -VOID -KiDeliverNormalApc(VOID); +VOID STDCALL KiDeliverApc(KPROCESSOR_MODE PreviousMode, + PVOID Reserved, + PKTRAP_FRAME TrapFrame); + +VOID KiInitializeUserApc(IN PVOID Reserved, + IN PKTRAP_FRAME TrapFrame, + IN PKNORMAL_ROUTINE NormalRoutine, + IN PVOID NormalContext, + IN PVOID SystemArgument1, + IN PVOID SystemArgument2); + +BOOLEAN +STDCALL +KeTestAlertThread(IN KPROCESSOR_MODE AlertMode); BOOLEAN STDCALL KeRemoveQueueApc (PKAPC Apc); PLIST_ENTRY STDCALL KeRundownQueue(IN PKQUEUE Queue); diff --git a/reactos/ntoskrnl/include/internal/ps.h b/reactos/ntoskrnl/include/internal/ps.h index 0c4b5829040..b927292fd86 100644 --- a/reactos/ntoskrnl/include/internal/ps.h +++ b/reactos/ntoskrnl/include/internal/ps.h @@ -16,7 +16,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* $Id: ps.h,v 1.72 2004/10/30 23:48:56 navaraf Exp $ +/* $Id: ps.h,v 1.73 2004/11/10 02:50:59 ion Exp $ * * FILE: ntoskrnl/ke/kthread.c * PURPOSE: Process manager definitions @@ -179,9 +179,11 @@ typedef struct typedef struct _ETHREAD { KTHREAD Tcb; - TIME CreateTime; - USHORT NestedFaultCount; - UCHAR ApcNeeded; + union { + TIME CreateTime; + UCHAR NestedFaultCount:2; + UCHAR ApcNeeded:1; + }; TIME ExitTime; LIST_ENTRY LpcReplyChain; NTSTATUS ExitStatus; @@ -476,6 +478,11 @@ NTSTATUS PsOpenTokenOfProcess(HANDLE ProcessHandle, NTSTATUS PsSuspendThread(PETHREAD Thread, PULONG PreviousCount); NTSTATUS PsResumeThread(PETHREAD Thread, PULONG PreviousCount); +VOID STDCALL PsExitSpecialApc(PKAPC Apc, + PKNORMAL_ROUTINE *NormalRoutine, + PVOID *NormalContext, + PVOID *SystemArgument1, + PVOID *SystemArgument2); #define THREAD_STATE_INITIALIZED (0) #define THREAD_STATE_READY (1) diff --git a/reactos/ntoskrnl/io/cleanup.c b/reactos/ntoskrnl/io/cleanup.c index c5fe3e93b3a..d54bf2bc3e7 100644 --- a/reactos/ntoskrnl/io/cleanup.c +++ b/reactos/ntoskrnl/io/cleanup.c @@ -166,11 +166,14 @@ IoSecondStageCompletion( PDEVICE_OBJECT DeviceObject; PFILE_OBJECT OriginalFileObject; PIRP Irp; - CCHAR PriorityBoost; - OriginalFileObject = (PFILE_OBJECT)(*NormalContext); - Irp = (PIRP)(*SystemArgument1); - PriorityBoost = (CCHAR)(LONG)(*SystemArgument2); + if (Apc) DPRINT("IoSecondStageCompletition with APC: %x\n", Apc); + + OriginalFileObject = (PFILE_OBJECT)(*SystemArgument1); + DPRINT("OriginalFileObject: %x\n", OriginalFileObject); + + Irp = CONTAINING_RECORD(Apc, IRP, Tail.Apc); + DPRINT("Irp: %x\n", Irp); /* * Note that we'll never see irp's flagged IRP_PAGING_IO (IRP_MOUNT_OPERATION) @@ -190,11 +193,10 @@ IoSecondStageCompletion( InitializeListHead(&Irp->ThreadListEntry); } - DPRINT("Tail Value %x, Irp Value %x\n", Irp->Tail.Overlay.CurrentStackLocation - (PIO_STACK_LOCATION)(Irp+1), Irp->CurrentLocation); IoStack = (PIO_STACK_LOCATION)(Irp+1) + Irp->CurrentLocation; DeviceObject = IoStack->DeviceObject; - DPRINT("IoSecondStageCompletion(Irp %x, PriorityBoost %d)\n", Irp, PriorityBoost); + DPRINT("IoSecondStageCompletion(Irp %x, PriorityBoost %d, MajorFunction %x)\n", Irp, PriorityBoost, IoStack->MajorFunction); switch (IoStack->MajorFunction) { @@ -240,7 +242,7 @@ IoSecondStageCompletion( if (Irp->UserEvent) { - KeSetEvent(Irp->UserEvent,PriorityBoost,FALSE); + KeSetEvent(Irp->UserEvent,0,FALSE); } //Windows NT File System Internals, page 169 @@ -248,11 +250,11 @@ IoSecondStageCompletion( { if (Irp->UserEvent == NULL) { - KeSetEvent(&OriginalFileObject->Event,PriorityBoost,FALSE); + KeSetEvent(&OriginalFileObject->Event,0,FALSE); } else if (OriginalFileObject->Flags & FO_SYNCHRONOUS_IO && Irp->UserEvent != &OriginalFileObject->Event) { - KeSetEvent(&OriginalFileObject->Event,PriorityBoost,FALSE); + KeSetEvent(&OriginalFileObject->Event,0,FALSE); } } @@ -290,7 +292,7 @@ IoSecondStageCompletion( KeInsertQueueApc( &Irp->Tail.Apc, Irp->UserIosb, NULL, - PriorityBoost); + 2); //NOTE: kernel (or rundown) routine frees the IRP diff --git a/reactos/ntoskrnl/io/irp.c b/reactos/ntoskrnl/io/irp.c index 88069bece62..460aff124ca 100644 --- a/reactos/ntoskrnl/io/irp.c +++ b/reactos/ntoskrnl/io/irp.c @@ -1,4 +1,4 @@ -/* $Id: irp.c,v 1.69 2004/10/31 22:21:41 ion Exp $ +/* $Id: irp.c,v 1.70 2004/11/10 02:50:59 ion Exp $ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel @@ -308,11 +308,8 @@ IofCompleteRequest(PIRP Irp, ASSERT(Irp->CancelRoutine == NULL); ASSERT(Irp->IoStatus.Status != STATUS_PENDING); - if (IoGetCurrentIrpStackLocation(Irp)->Control & SL_PENDING_RETURNED) - { - Irp->PendingReturned = TRUE; - } - + Irp->PendingReturned = IoGetCurrentIrpStackLocation(Irp)->Control & SL_PENDING_RETURNED; + /* * Run the completion routines. */ @@ -455,6 +452,7 @@ IofCompleteRequest(PIRP Irp, BOOLEAN bStatus; DPRINT("Dispatching APC\n"); + KeInitializeApc( &Irp->Tail.Apc, &Irp->Tail.Overlay.Thread->Tcb, Irp->ApcEnvironment, @@ -462,11 +460,11 @@ IofCompleteRequest(PIRP Irp, NULL, (PKNORMAL_ROUTINE) NULL, KernelMode, - OriginalFileObject); + NULL); bStatus = KeInsertQueueApc(&Irp->Tail.Apc, - (PVOID)Irp, - (PVOID)(ULONG)PriorityBoost, + (PVOID)OriginalFileObject, + NULL, // This is used for REPARSE stuff PriorityBoost); if (bStatus == FALSE) @@ -480,7 +478,7 @@ IofCompleteRequest(PIRP Irp, { DPRINT("Calling IoSecondStageCompletion routine directly\n"); KeRaiseIrql(APC_LEVEL, &oldIrql); - IoSecondStageCompletion(NULL,NULL,(PVOID)&OriginalFileObject,(PVOID) &Irp,(PVOID) &PriorityBoost); + IoSecondStageCompletion(&Irp->Tail.Apc,NULL,NULL,(PVOID)&OriginalFileObject, NULL); KeLowerIrql(oldIrql); DPRINT("Finished completition routine\n"); } diff --git a/reactos/ntoskrnl/ke/apc.c b/reactos/ntoskrnl/ke/apc.c index feecbb63d1f..eecdfeaad7a 100644 --- a/reactos/ntoskrnl/ke/apc.c +++ b/reactos/ntoskrnl/ke/apc.c @@ -41,267 +41,71 @@ VOID PsTerminateCurrentThread(NTSTATUS ExitStatus); /* FUNCTIONS *****************************************************************/ +/* + * @implemented + */ +VOID +STDCALL +KeInitializeApc( + IN PKAPC Apc, + IN PKTHREAD Thread, + IN KAPC_ENVIRONMENT TargetEnvironment, + IN PKKERNEL_ROUTINE KernelRoutine, + IN PKRUNDOWN_ROUTINE RundownRoutine OPTIONAL, + IN PKNORMAL_ROUTINE NormalRoutine, + IN KPROCESSOR_MODE Mode, + IN PVOID Context) +/* + * FUNCTION: Initialize an APC object + * ARGUMENTS: + * Apc = Pointer to the APC object to initialized + * Thread = Thread the APC is to be delivered to + * TargetEnvironment = APC environment to use + * KernelRoutine = Routine to be called for a kernel-mode APC + * RundownRoutine = Routine to be called if the thread has exited with + * the APC being executed + * NormalRoutine = Routine to be called for a user-mode APC + * Mode = APC mode + * Context = Parameter to be passed to the APC routine + */ +{ + DPRINT ("KeInitializeApc(Apc %x, Thread %x, Environment %d, " + "KernelRoutine %x, RundownRoutine %x, NormalRoutine %x, Mode %d, " + "Context %x)\n",Apc,Thread,TargetEnvironment,KernelRoutine,RundownRoutine, + NormalRoutine,Mode,Context); + + /* Set up the basic APC Structure Data */ + RtlZeroMemory(Apc, sizeof(KAPC)); + Apc->Type = KApc; + Apc->Size = sizeof(KAPC); + + /* Set the Environment */ + if (TargetEnvironment == CurrentApcEnvironment) { + Apc->ApcStateIndex = Thread->ApcStateIndex; + } else { + Apc->ApcStateIndex = TargetEnvironment; + } + + /* Set the Thread and Routines */ + Apc->Thread = Thread; + Apc->KernelRoutine = KernelRoutine; + Apc->RundownRoutine = RundownRoutine; + Apc->NormalRoutine = NormalRoutine; + + /* Check if this is a Special APC, in which case we use KernelMode and no Context */ + if (ARGUMENT_PRESENT(NormalRoutine)) { + Apc->ApcMode = Mode; + Apc->NormalContext = Context; + } else { + Apc->ApcMode = KernelMode; + } +} + /* * @implemented */ BOOLEAN STDCALL -KeAreApcsDisabled( - VOID - ) -{ - return KeGetCurrentThread()->KernelApcDisable ? FALSE : TRUE; -} - -VOID KiRundownThread(VOID) -/* - * FUNCTION: - */ -{ -} - -BOOLEAN KiTestAlert(VOID) -/* - * FUNCTION: Tests whether there are any pending APCs for the current thread - * and if so the APCs will be delivered on exit from kernel mode - */ -{ - KIRQL oldIrql; - - oldIrql = KeRaiseIrqlToDpcLevel(); - if (KeGetCurrentThread()->ApcState.UserApcPending == 0) - { - KeLowerIrql(oldIrql); - return(FALSE); - } - KeGetCurrentThread()->Alerted[0] = 1; - KeLowerIrql(oldIrql); - return(TRUE); -} - -VOID -KiDeliverNormalApc(VOID) -{ - PETHREAD Thread = PsGetCurrentThread(); - PLIST_ENTRY current; - PKAPC Apc; - KIRQL oldlvl; - PKNORMAL_ROUTINE NormalRoutine; - PVOID NormalContext; - PVOID SystemArgument1; - PVOID SystemArgument2; - - oldlvl = KeRaiseIrqlToDpcLevel(); - while(!IsListEmpty(&(Thread->Tcb.ApcState.ApcListHead[0]))) - { - current = RemoveTailList(&Thread->Tcb.ApcState.ApcListHead[0]); - Apc = CONTAINING_RECORD(current, KAPC, ApcListEntry); - if (Apc->NormalRoutine == NULL) - { - DbgPrint("Exiting kernel with kernel APCs pending.\n"); - KEBUGCHECKEX(KERNEL_APC_PENDING_DURING_EXIT, (ULONG)Apc, - Thread->Tcb.KernelApcDisable, oldlvl, 0); - } - Apc->Inserted = FALSE; - Thread->Tcb.ApcState.KernelApcInProgress++; - Thread->Tcb.ApcState.KernelApcPending--; - - KeLowerIrql(oldlvl); - - ASSERT(Apc->KernelRoutine); - - NormalRoutine = Apc->NormalRoutine; - NormalContext = Apc->NormalContext; - SystemArgument1 = Apc->SystemArgument1; - SystemArgument2 = Apc->SystemArgument2; - Apc->KernelRoutine(Apc, - &NormalRoutine, - &NormalContext, - &SystemArgument1, - &SystemArgument2); - NormalRoutine(NormalContext, SystemArgument1, SystemArgument2); - - oldlvl = KeRaiseIrqlToDpcLevel(); - Thread->Tcb.ApcState.KernelApcInProgress--; - } - KeLowerIrql(oldlvl); -} - -BOOLEAN -KiDeliverUserApc(PKTRAP_FRAME TrapFrame) -/* - * FUNCTION: Tests whether there are any pending APCs for the current thread - * and if so the APCs will be delivered on exit from kernel mode. - * ARGUMENTS: - * Thread = Thread to test for alerts - * UserContext = The user context saved on entry to kernel mode - */ -{ - PLIST_ENTRY current_entry; - PKAPC Apc; - PULONG Esp; - PCONTEXT Context; - KIRQL oldlvl; - PKTHREAD Thread; - - DPRINT("KiDeliverUserApc(TrapFrame %x/%x)\n", TrapFrame, - KeGetCurrentThread()->TrapFrame); - Thread = KeGetCurrentThread(); - - /* - * Check for thread termination - */ - - oldlvl = KeRaiseIrqlToDpcLevel(); - - current_entry = Thread->ApcState.ApcListHead[1].Flink; - - /* - * Shouldn't happen but check anyway. - */ - if (current_entry == &Thread->ApcState.ApcListHead[1]) - { - KeLowerIrql(oldlvl); - DbgPrint("KiDeliverUserApc called but no APC was pending\n"); - return(FALSE); - } - - while (!IsListEmpty(&Thread->ApcState.ApcListHead[1])) - { - current_entry = RemoveHeadList(&Thread->ApcState.ApcListHead[1]); - Apc = CONTAINING_RECORD(current_entry, KAPC, ApcListEntry); - Apc->Inserted = FALSE; - - /* - * We've dealt with one pending user-mode APC - */ - Thread->ApcState.UserApcPending--; - KeLowerIrql(oldlvl); - - /* - * Save the thread's current context (in other words the registers - * that will be restored when it returns to user mode) so the - * APC dispatcher can restore them later - */ - Context = (PCONTEXT)(((PUCHAR)TrapFrame->Esp) - sizeof(CONTEXT)); - memset(Context, 0, sizeof(CONTEXT)); - Context->ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER | - CONTEXT_SEGMENTS | CONTEXT_i386; - Context->SegGs = TrapFrame->Gs; - Context->SegFs = TrapFrame->Fs; - Context->SegEs = TrapFrame->Es; - Context->SegDs = TrapFrame->Ds; - Context->Edi = TrapFrame->Edi; - Context->Esi = TrapFrame->Esi; - Context->Ebx = TrapFrame->Ebx; - Context->Edx = TrapFrame->Edx; - Context->Ecx = TrapFrame->Ecx; - Context->Eax = TrapFrame->Eax; - Context->Ebp = TrapFrame->Ebp; - Context->Eip = TrapFrame->Eip; - Context->SegCs = TrapFrame->Cs; - Context->EFlags = TrapFrame->Eflags; - Context->Esp = TrapFrame->Esp; - Context->SegSs = TrapFrame->Ss; - - /* - * Setup the trap frame so the thread will start executing at the - * APC Dispatcher when it returns to user-mode - */ - Esp = (PULONG)(((PUCHAR)TrapFrame->Esp) - - (sizeof(CONTEXT) + (6 * sizeof(ULONG)))); - - Esp[0] = 0xdeadbeef; - Esp[1] = (ULONG)Apc->NormalRoutine; - Esp[2] = (ULONG)Apc->NormalContext; - Esp[3] = (ULONG)Apc->SystemArgument1; - Esp[4] = (ULONG)Apc->SystemArgument2; - Esp[5] = (ULONG)Context; - TrapFrame->Eip = (ULONG)LdrpGetSystemDllApcDispatcher(); - TrapFrame->Esp = (ULONG)Esp; - - - /* - * Now call for the kernel routine for the APC, which will free - * the APC data structure, we can't do this ourselves because - * the APC may be embedded in some larger structure e.g. an IRP - * We also give the kernel routine a last chance to modify the - * arguments to the user APC routine. - */ - ASSERT(Apc->KernelRoutine); - Apc->KernelRoutine(Apc, - (PKNORMAL_ROUTINE*)&Esp[1], - (PVOID*)&Esp[2], - (PVOID*)&Esp[3], - (PVOID*)&Esp[4]); - - oldlvl = KeRaiseIrqlToDpcLevel(); - } - Thread->Alerted[0] = 0; - KeLowerIrql(oldlvl); - - return(TRUE); -} - -/* - * @implemented - */ -VOID STDCALL -KiDeliverApc(ULONG Unknown1, - ULONG Unknown2, - ULONG Unknown3) -/* - * FUNCTION: Deliver an APC to the current thread. - * NOTES: This is called from the IRQL switching code if the current thread - * is returning from an IRQL greater than or equal to APC_LEVEL to - * PASSIVE_LEVEL and there are kernel-mode APCs pending. This means any - * pending APCs will be delivered after a thread gets a new quantum and - * after it wakes from a wait. - */ -{ - PETHREAD Thread = PsGetCurrentThread(); - PLIST_ENTRY current_entry; - PKAPC Apc; - KIRQL oldlvl; - - DPRINT("KiDeliverApc()\n"); - oldlvl = KeRaiseIrqlToDpcLevel(); - current_entry = Thread->Tcb.ApcState.ApcListHead[0].Flink; - while(current_entry != &Thread->Tcb.ApcState.ApcListHead[0]) - { - Apc = CONTAINING_RECORD(current_entry, KAPC, ApcListEntry); - if (Apc->NormalRoutine == NULL) - { - Apc->Inserted = FALSE; - RemoveEntryList(&Apc->ApcListEntry); - Thread->Tcb.ApcState.KernelApcInProgress++; - Thread->Tcb.ApcState.KernelApcPending--; - - KeLowerIrql(oldlvl); - - ASSERT(Apc->KernelRoutine); - Apc->KernelRoutine(Apc, - &Apc->NormalRoutine, - &Apc->NormalContext, - &Apc->SystemArgument1, - &Apc->SystemArgument2); - - oldlvl = KeRaiseIrqlToDpcLevel(); - Thread->Tcb.ApcState.KernelApcInProgress--; - current_entry = Thread->Tcb.ApcState.ApcListHead[0].Flink; - } - else - { - current_entry = current_entry->Flink; - } - } - KeLowerIrql(oldlvl); -} - -/* - * @implemented - */ -BOOLEAN STDCALL KeInsertQueueApc (PKAPC Apc, PVOID SystemArgument1, PVOID SystemArgument2, @@ -310,124 +114,102 @@ KeInsertQueueApc (PKAPC Apc, * FUNCTION: Queues an APC for execution * ARGUMENTS: * Apc = APC to be queued - * SystemArgument[1-2] = TBD - * Mode = TBD + * SystemArgument[1-2] = Arguments we ignore and simply pass on. + * PriorityBoost = Priority Boost to give to the Thread */ { - //FIXME: return FALSE if APC can't be queued to target thread (thread has ended) - KIRQL oldlvl; - PKTHREAD TargetThread; + KIRQL OldIrql; + PKTHREAD Thread; + PLIST_ENTRY ApcListEntry; + PKAPC QueuedApc; - DPRINT("KeInsertQueueApc(Apc %x, SystemArgument1 %x, " - "SystemArgument2 %x)\n",Apc,SystemArgument1, - SystemArgument2); + DPRINT ("KeInsertQueueApc(Apc %x, SystemArgument1 %x, " + "SystemArgument2 %x)\n",Apc,SystemArgument1, + SystemArgument2); - Apc->SystemArgument1 = SystemArgument1; - Apc->SystemArgument2 = SystemArgument2; - - if (Apc->Inserted) - { -#if 0 - /* TMN: This code is in error */ - DbgPrint("KeInsertQueueApc(): multiple APC insertations\n"); - KEBUGCHECK(0); -#else - return FALSE; -#endif - } - - oldlvl = KeRaiseIrqlToDpcLevel(); - - TargetThread = Apc->Thread; - - if (TargetThread->State == THREAD_STATE_TERMINATED_1 || - TargetThread->State == THREAD_STATE_TERMINATED_2) - { - KeLowerIrql(oldlvl); - return(FALSE); - } - - if (Apc->ApcMode == KernelMode) - { - InsertTailList(&TargetThread->ApcStatePointer[(int) Apc->ApcStateIndex]->ApcListHead[0], - &Apc->ApcListEntry); - TargetThread->ApcStatePointer[(int) Apc->ApcStateIndex]->KernelApcPending++; - } - else - { - InsertTailList(&TargetThread->ApcStatePointer[(int) Apc->ApcStateIndex]->ApcListHead[1], - &Apc->ApcListEntry); - TargetThread->ApcStatePointer[(int) Apc->ApcStateIndex]->UserApcPending++; - } - Apc->Inserted = TRUE; - - /* - * If this is a kernel-mode APC for the current thread and we are not - * inside a critical section or at APC level then call it, in fact we - * rely on the side effects of dropping the IRQL level when we release - * the spinlock - */ - if (Apc->ApcMode == KernelMode && TargetThread == KeGetCurrentThread() && - Apc->NormalRoutine == NULL) - { - HalRequestSoftwareInterrupt(APC_LEVEL); - KeLowerIrql(oldlvl); - return TRUE; - } - - /* - * If this is a kernel-mode APC and it is waiting at PASSIVE_LEVEL and - * not inside a critical section then wake it up. Otherwise it will - * execute the APC as soon as it returns to PASSIVE_LEVEL. - * FIXME: If the thread is running on another processor then send an - * IPI. - * FIXME: Check if the thread is terminating. - */ - if (Apc->ApcMode == KernelMode && TargetThread->WaitIrql < APC_LEVEL && - Apc->NormalRoutine == NULL) - { - KeRemoveAllWaitsThread(CONTAINING_RECORD(TargetThread, ETHREAD, Tcb), - STATUS_KERNEL_APC, TRUE); - } - - /* - * If this is a 'funny' user-mode APC then mark the thread as - * alerted so it will execute the APC on exit from kernel mode. If it - * is waiting alertably then wake it up so it can return to user mode. - */ - if (Apc->ApcMode == KernelMode && Apc->NormalRoutine != NULL) - { - TargetThread->Alerted[1] = 1; - if (TargetThread->Alertable == TRUE && - TargetThread->WaitMode == UserMode) - { - PETHREAD Thread; - - Thread = CONTAINING_RECORD(TargetThread, ETHREAD, Tcb); - KeRemoveAllWaitsThread(Thread, STATUS_USER_APC, TRUE); - } - } - - /* - * If the thread is waiting alertably then wake it up and it will - * return to to user-mode executing the APC in the process. Otherwise the - * thread will execute the APC next time it enters an alertable wait. - */ - if (Apc->ApcMode == UserMode && TargetThread->Alertable == TRUE && - TargetThread->WaitMode == UserMode) - { - NTSTATUS Status; + /* FIXME: Implement Dispatcher Lock */ + OldIrql = KeRaiseIrqlToDpcLevel(); - DPRINT("Resuming thread for user APC\n"); + /* Get the Thread specified in the APC */ + Thread = Apc->Thread; + + /* Make sure the thread allows APC Queues */ + if (Thread->ApcQueueable == FALSE) { + DPRINT("Thread doesn't allow APC Queues\n"); + KeLowerIrql(OldIrql); + return FALSE; + } - Status = STATUS_USER_APC; - TargetThread->Alerted[0] = 1; - KeRemoveAllWaitsThread(CONTAINING_RECORD(TargetThread, ETHREAD, Tcb), - STATUS_USER_APC, TRUE); - } - HalRequestSoftwareInterrupt(APC_LEVEL); - KeLowerIrql(oldlvl); - return TRUE; + /* Set the System Arguments */ + Apc->SystemArgument1 = SystemArgument1; + Apc->SystemArgument2 = SystemArgument2; + + /* Don't do anything if the APC is already inserted */ + if (Apc->Inserted) { + KeLowerIrql(OldIrql); + return FALSE; + } + + /* Three scenarios: + 1) Kernel APC with Normal Routine or User APC = Put it at the end of the List + 2) User APC which is PsExitSpecialApc = Put it at the front of the List + 3) Kernel APC without Normal Routine = Put it at the end of the No-Normal Routine Kernel APC list + */ + if ((Apc->ApcMode != KernelMode) && (Apc->KernelRoutine == (PKKERNEL_ROUTINE)PsExitSpecialApc)) { + DPRINT ("Inserting the Process Exit APC into the Queue\n"); + Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->UserApcPending = TRUE; + InsertHeadList(&Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->ApcListHead[(int)Apc->ApcMode], + &Apc->ApcListEntry); + } else if (Apc->NormalRoutine == NULL) { + DPRINT ("Inserting Special APC %x into the Queue\n", Apc); + for (ApcListEntry = Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->ApcListHead[(int)Apc->ApcMode].Flink; + ApcListEntry != &Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->ApcListHead[(int)Apc->ApcMode]; + ApcListEntry = ApcListEntry->Flink) { + + QueuedApc = CONTAINING_RECORD(ApcListEntry, KAPC, ApcListEntry); + if (Apc->NormalRoutine != NULL) break; + } + + /* We found the first "Normal" APC, so write right before it */ + ApcListEntry = ApcListEntry->Blink; + InsertHeadList(ApcListEntry, &Apc->ApcListEntry); + } else { + DPRINT ("Inserting Normal APC %x into the %x Queue\n", Apc, Apc->ApcMode); + InsertTailList(&Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->ApcListHead[(int)Apc->ApcMode], + &Apc->ApcListEntry); + } + + /* Confirm Insertion */ + Apc->Inserted = TRUE; + + /* Three possibilites here again: + 1) Kernel APC, The thread is Running: Request an Interrupt + 2) Kernel APC, The Thread is Waiting at PASSIVE_LEVEL and APCs are enabled and not in progress: Unwait the Thread + 3) User APC, Unwait the Thread if it is alertable + */ + if (Apc->ApcMode == KernelMode) { + Thread->ApcState.KernelApcPending = TRUE; + if (Thread->State == THREAD_STATE_RUNNING) { + /* FIXME: Use IPI */ + DPRINT ("Requesting APC Interrupt for Running Thread \n"); + HalRequestSoftwareInterrupt(APC_LEVEL); + } else if ((Thread->WaitIrql < APC_LEVEL) && (Apc->NormalRoutine == NULL)) { + DPRINT ("Waking up Thread for Kernel-Mode APC Delivery \n"); + KeRemoveAllWaitsThread(CONTAINING_RECORD(Thread, ETHREAD, Tcb), + STATUS_KERNEL_APC, + TRUE); + } + } else if ((Thread->WaitMode == UserMode) && (Thread->Alertable)) { + DPRINT ("Waking up Thread for User-Mode APC Delivery \n"); + Thread->ApcState.UserApcPending = TRUE; + KeRemoveAllWaitsThread(CONTAINING_RECORD(Thread, ETHREAD, Tcb), + STATUS_USER_APC, + TRUE); + } + + /* Return Sucess if we are here */ + KeLowerIrql(OldIrql); + return TRUE; } BOOLEAN STDCALL @@ -441,92 +223,292 @@ KeRemoveQueueApc (PKAPC Apc) * NOTE: This function is not exported. */ { - KIRQL oldIrql; - PKTHREAD TargetThread; + KIRQL OldIrql; + PKTHREAD Thread = Apc->Thread; - oldIrql = KeRaiseIrqlToDpcLevel(); - if (Apc->Inserted == FALSE) - { - KeLowerIrql(oldIrql); - return FALSE; - } - - TargetThread = Apc->Thread; - RemoveEntryList(&Apc->ApcListEntry); - if (Apc->ApcMode == KernelMode) - { - TargetThread->ApcStatePointer[(int) Apc->ApcStateIndex]->KernelApcPending--; - } - else - { - TargetThread->ApcStatePointer[(int) Apc->ApcStateIndex]->UserApcPending--; - } - Apc->Inserted = FALSE; - - KeLowerIrql(oldIrql); - return(TRUE); + DPRINT("KeRemoveQueueApc called for APC: %x \n", Apc); + + /* FIXME: Implement Dispatcher Lock */ + OldIrql = KeRaiseIrqlToDpcLevel(); + KeAcquireSpinLock(&Thread->ApcQueueLock, &OldIrql); + + /* Remove it from the Queue if it's inserted */ + if (!Apc->Inserted == FALSE) { + RemoveEntryList(&Apc->ApcListEntry); + Apc->Inserted = FALSE; + + /* If the Queue is completely empty, then no more APCs are pending */ + if (IsListEmpty(&Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->ApcListHead[(int)Apc->ApcMode])) { + if (Apc->ApcMode == KernelMode) { + Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->KernelApcPending = FALSE; + } else { + Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->UserApcPending = FALSE; + } + } + } else { + KeReleaseSpinLock(&Thread->ApcQueueLock, OldIrql); + KeLowerIrql(OldIrql); + return(FALSE); + } + + /* Restore IRQL and Return */ + KeReleaseSpinLock(&Thread->ApcQueueLock, OldIrql); + KeLowerIrql(OldIrql); + return(TRUE); } +BOOLEAN +STDCALL +KeTestAlertThread(IN KPROCESSOR_MODE AlertMode) +/* + * FUNCTION: Tests whether there are any pending APCs for the current thread + * and if so the APCs will be delivered on exit from kernel mode + */ +{ + KIRQL OldIrql; + PKTHREAD Thread = KeGetCurrentThread(); + BOOLEAN OldState; + + /* FIXME: Implement Dispatcher Lock */ + OldIrql = KeRaiseIrqlToDpcLevel(); + KeAcquireSpinLock(&Thread->ApcQueueLock, &OldIrql); + + OldState = Thread->Alerted[(int)AlertMode]; + + /* If the Thread is Alerted, Clear it */ + if (OldState) { + Thread->Alerted[(int)AlertMode] = FALSE; + } else if ((AlertMode == UserMode) && (!IsListEmpty(&Thread->ApcState.ApcListHead[UserMode]))) { + /* If the mode is User and the Queue isn't empty, set Pending */ + Thread->ApcState.UserApcPending = TRUE; + } + + /* FIXME: Implement Dispatcher Lock */ + KeReleaseSpinLock(&Thread->ApcQueueLock, OldIrql); + KeLowerIrql(OldIrql); + return OldState; +} /* * @implemented */ -VOID STDCALL -KeInitializeApc( - IN PKAPC Apc, - IN PKTHREAD Thread, - IN KAPC_ENVIRONMENT TargetEnvironment, - IN PKKERNEL_ROUTINE KernelRoutine, - IN PKRUNDOWN_ROUTINE RundownRoutine OPTIONAL, - IN PKNORMAL_ROUTINE NormalRoutine, - IN KPROCESSOR_MODE Mode, - IN PVOID Context) +VOID +STDCALL +KiDeliverApc(KPROCESSOR_MODE PreviousMode, + PVOID Reserved, + PKTRAP_FRAME TrapFrame) /* - * FUNCTION: Initialize an APC object - * ARGUMENTS: - * Apc = Pointer to the APC object to initialized - * Thread = Thread the APC is to be delivered to - * StateIndex = KAPC_ENVIRONMENT - * KernelRoutine = Routine to be called for a kernel-mode APC - * RundownRoutine = Routine to be called if the thread has exited with - * the APC being executed - * NormalRoutine = Routine to be called for a user-mode APC - * Mode = APC mode - * Context = Parameter to be passed to the APC routine + * FUNCTION: Deliver an APC to the current thread. + * NOTES: This is called from the IRQL switching code if the current thread + * is returning from an IRQL greater than or equal to APC_LEVEL to + * PASSIVE_LEVEL and there are kernel-mode APCs pending. This means any + * pending APCs will be delivered after a thread gets a new quantum and + * after it wakes from a wait. Note that the TrapFrame is only valid if + * the previous mode is User. */ { - DPRINT("KeInitializeApc(Apc %x, Thread %x, Environment %d, " - "KernelRoutine %x, RundownRoutine %x, NormalRoutine %x, Mode %d, " - "Context %x)\n",Apc,Thread,TargetEnvironment,KernelRoutine,RundownRoutine, - NormalRoutine,Mode,Context); + PKTHREAD Thread = KeGetCurrentThread(); + PLIST_ENTRY ApcListEntry; + PKAPC Apc; + KIRQL OldIrql; + PKKERNEL_ROUTINE KernelRoutine; + PVOID NormalContext; + PKNORMAL_ROUTINE NormalRoutine; + PVOID SystemArgument1; + PVOID SystemArgument2; - memset(Apc, 0, sizeof(KAPC)); - Apc->Thread = Thread; - Apc->ApcListEntry.Flink = NULL; - Apc->ApcListEntry.Blink = NULL; - Apc->KernelRoutine = KernelRoutine; - Apc->RundownRoutine = RundownRoutine; - Apc->NormalRoutine = NormalRoutine; - Apc->NormalContext = Context; - Apc->Inserted = FALSE; + /* Lock the APC Queue and Raise IRQL to Synch */ + KeAcquireSpinLock(&Thread->ApcQueueLock, &OldIrql); - if (TargetEnvironment == CurrentApcEnvironment) - { - Apc->ApcStateIndex = Thread->ApcStateIndex; - } - else - { - Apc->ApcStateIndex = TargetEnvironment; - } + /* Clear APC Pending */ + Thread->ApcState.KernelApcPending = FALSE; + + /* Do the Kernel APCs first */ + while (!IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode])) { + + /* Get the next Entry */ + ApcListEntry = Thread->ApcState.ApcListHead[KernelMode].Flink; + Apc = CONTAINING_RECORD(ApcListEntry, KAPC, ApcListEntry); + + /* Save Parameters so that it's safe to free the Object in Kernel Routine*/ + NormalRoutine = Apc->NormalRoutine; + KernelRoutine = Apc->KernelRoutine; + NormalContext = Apc->NormalContext; + SystemArgument1 = Apc->SystemArgument1; + SystemArgument2 = Apc->SystemArgument2; + + /* Special APC */ + if (NormalRoutine == NULL) { + /* Remove the APC from the list */ + Apc->Inserted = FALSE; + RemoveEntryList(ApcListEntry); + + /* Go back to APC_LEVEL */ + KeReleaseSpinLock(&Thread->ApcQueueLock, OldIrql); + + /* Call the Special APC */ + DPRINT("Delivering a Special APC: %x\n", Apc); + KernelRoutine(Apc, + &NormalRoutine, + &NormalContext, + &SystemArgument1, + &SystemArgument2); - if (Apc->NormalRoutine != NULL) - { - Apc->ApcMode = Mode; - } - else - { - Apc->ApcMode = KernelMode; - } + /* Raise IRQL and Lock again */ + KeAcquireSpinLock(&Thread->ApcQueueLock, &OldIrql); + } else { + /* Normal Kernel APC */ + if (Thread->ApcState.KernelApcInProgress || Thread->KernelApcDisable) { + KeReleaseSpinLock(&Thread->ApcQueueLock, OldIrql); + return; + } + + /* Dequeue the APC */ + RemoveEntryList(ApcListEntry); + Apc->Inserted = FALSE; + + /* Go back to APC_LEVEL */ + KeReleaseSpinLock(&Thread->ApcQueueLock, OldIrql); + + /* Call the Kernel APC */ + DPRINT("Delivering a Normal APC: %x\n", Apc); + KernelRoutine(Apc, + &NormalRoutine, + &NormalContext, + &SystemArgument1, + &SystemArgument2); + + /* If There still is a Normal Routine, then we need to call this at PASSIVE_LEVEL */ + if (NormalRoutine != NULL) { + /* At Passive Level, this APC can be prempted by a Special APC */ + Thread->ApcState.KernelApcInProgress = TRUE; + KeLowerIrql(PASSIVE_LEVEL); + + /* Call and Raise IRQ back to APC_LEVEL */ + DPRINT("Calling the Normal Routine for a Normal APC: %x\n", Apc); + NormalRoutine(&NormalContext, &SystemArgument1, &SystemArgument2); + KeRaiseIrql(APC_LEVEL, &OldIrql); + } + + /* Raise IRQL and Lock again */ + KeAcquireSpinLock(&Thread->ApcQueueLock, &OldIrql); + Thread->ApcState.KernelApcInProgress = FALSE; + } + } + + /* Now we do the User APCs */ + if ((!IsListEmpty(&Thread->ApcState.ApcListHead[UserMode])) && + (PreviousMode == UserMode) && + (Thread->ApcState.UserApcPending == TRUE)) { + + /* It's not pending anymore */ + Thread->ApcState.UserApcPending = FALSE; + + /* Get the APC Object */ + ApcListEntry = Thread->ApcState.ApcListHead[UserMode].Flink; + Apc = CONTAINING_RECORD(ApcListEntry, KAPC, ApcListEntry); + + /* Save Parameters so that it's safe to free the Object in Kernel Routine*/ + NormalRoutine = Apc->NormalRoutine; + KernelRoutine = Apc->KernelRoutine; + NormalContext = Apc->NormalContext; + SystemArgument1 = Apc->SystemArgument1; + SystemArgument2 = Apc->SystemArgument2; + + /* Remove the APC from Queue, restore IRQL and call the APC */ + RemoveEntryList(ApcListEntry); + KeReleaseSpinLock(&Thread->ApcQueueLock, OldIrql); + DPRINT("Calling the Kernel Routine for for a User APC: %x\n", Apc); + KernelRoutine(Apc, + &NormalRoutine, + &NormalContext, + &SystemArgument1, + &SystemArgument2); + + if (NormalRoutine == NULL) { + /* Check if more User APCs are Pending */ + KeTestAlertThread(UserMode); + } else { + /* Set up the Trap Frame and prepare for Execution in NTDLL.DLL */ + DPRINT("Delivering a User APC: %x\n", Apc); + KiInitializeUserApc(Reserved, + TrapFrame, + NormalRoutine, + NormalContext, + SystemArgument1, + SystemArgument2); + } + } else { + /* Go back to APC_LEVEL */ + KeReleaseSpinLock(&Thread->ApcQueueLock, OldIrql); + } +} + +VOID KiInitializeUserApc(IN PVOID Reserved, + IN PKTRAP_FRAME TrapFrame, + IN PKNORMAL_ROUTINE NormalRoutine, + IN PVOID NormalContext, + IN PVOID SystemArgument1, + IN PVOID SystemArgument2) +/* + * FUNCTION: Prepares the Context for a user mode APC through ntdll.dll + */ +{ + PCONTEXT Context; + PULONG Esp; + + DPRINT("KiInitializeUserApc(TrapFrame %x/%x)\n", TrapFrame, KeGetCurrentThread()->TrapFrame); + + /* + * Save the thread's current context (in other words the registers + * that will be restored when it returns to user mode) so the + * APC dispatcher can restore them later + */ + Context = (PCONTEXT)(((PUCHAR)TrapFrame->Esp) - sizeof(CONTEXT)); + RtlZeroMemory(Context, sizeof(CONTEXT)); + Context->ContextFlags = CONTEXT_FULL; + Context->SegGs = TrapFrame->Gs; + Context->SegFs = TrapFrame->Fs; + Context->SegEs = TrapFrame->Es; + Context->SegDs = TrapFrame->Ds; + Context->Edi = TrapFrame->Edi; + Context->Esi = TrapFrame->Esi; + Context->Ebx = TrapFrame->Ebx; + Context->Edx = TrapFrame->Edx; + Context->Ecx = TrapFrame->Ecx; + Context->Eax = TrapFrame->Eax; + Context->Ebp = TrapFrame->Ebp; + Context->Eip = TrapFrame->Eip; + Context->SegCs = TrapFrame->Cs; + Context->EFlags = TrapFrame->Eflags; + Context->Esp = TrapFrame->Esp; + Context->SegSs = TrapFrame->Ss; + + /* + * Setup the trap frame so the thread will start executing at the + * APC Dispatcher when it returns to user-mode + */ + Esp = (PULONG)(((PUCHAR)TrapFrame->Esp) - (sizeof(CONTEXT) + (6 * sizeof(ULONG)))); + Esp[0] = 0xdeadbeef; + Esp[1] = (ULONG)NormalRoutine; + Esp[2] = (ULONG)NormalContext; + Esp[3] = (ULONG)SystemArgument1; + Esp[4] = (ULONG)SystemArgument2; + Esp[5] = (ULONG)Context; + TrapFrame->Eip = (ULONG)LdrpGetSystemDllApcDispatcher(); + TrapFrame->Esp = (ULONG)Esp; +} + +/* + * @implemented + */ +BOOLEAN +STDCALL +KeAreApcsDisabled( + VOID + ) +{ + return KeGetCurrentThread()->KernelApcDisable ? FALSE : TRUE; } VOID STDCALL @@ -597,8 +579,11 @@ NtQueueApcThread(HANDLE ThreadHandle, NTSTATUS STDCALL NtTestAlert(VOID) { - KiTestAlert(); - return(STATUS_SUCCESS); + if (KeTestAlertThread(KeGetPreviousMode())) { + return STATUS_ALERTED; + } else { + return STATUS_SUCCESS; + } } VOID INIT_FUNCTION diff --git a/reactos/ntoskrnl/ke/i386/irq.c b/reactos/ntoskrnl/ke/i386/irq.c index 19a9f93958a..dc40a0e5c2f 100644 --- a/reactos/ntoskrnl/ke/i386/irq.c +++ b/reactos/ntoskrnl/ke/i386/irq.c @@ -16,7 +16,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* $Id: irq.c,v 1.54 2004/11/07 22:55:38 navaraf Exp $ +/* $Id: irq.c,v 1.55 2004/11/10 02:51:00 ion Exp $ * * PROJECT: ReactOS kernel * FILE: ntoskrnl/ke/i386/irq.c @@ -361,7 +361,7 @@ KiInterruptDispatch (ULONG vector, PKIRQ_TRAPFRAME Trapframe) CurrentThread->TrapFrame = &KernelTrapFrame; } - KiDeliverNormalApc(); + KiDeliverApc(KernelMode, NULL, NULL); ASSERT(KeGetCurrentThread() == CurrentThread); if (CurrentThread->TrapFrame == &KernelTrapFrame) diff --git a/reactos/ntoskrnl/ke/i386/usercall.c b/reactos/ntoskrnl/ke/i386/usercall.c index c0a548ad6d3..589baa01e49 100644 --- a/reactos/ntoskrnl/ke/i386/usercall.c +++ b/reactos/ntoskrnl/ke/i386/usercall.c @@ -1,4 +1,4 @@ -/* $Id: usercall.c,v 1.30 2004/10/22 20:32:49 ekohl Exp $ +/* $Id: usercall.c,v 1.31 2004/11/10 02:51:00 ion Exp $ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel @@ -43,11 +43,11 @@ KiAfterSystemCallHook(PKTRAP_FRAME TrapFrame) { if (KeGetCurrentThread()->Alerted[1] != 0 && TrapFrame->Cs != KERNEL_CS) { - KiDeliverNormalApc(); + KiDeliverApc(KernelMode, NULL, NULL); } if (KeGetCurrentThread()->Alerted[0] != 0 && TrapFrame->Cs != KERNEL_CS) { - KiDeliverUserApc(TrapFrame); + KiDeliverApc(UserMode, NULL, TrapFrame); } } diff --git a/reactos/ntoskrnl/ke/kthread.c b/reactos/ntoskrnl/ke/kthread.c index 7b9889db1da..d7701b18ceb 100644 --- a/reactos/ntoskrnl/ke/kthread.c +++ b/reactos/ntoskrnl/ke/kthread.c @@ -16,7 +16,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* $Id: kthread.c,v 1.57 2004/11/07 22:55:38 navaraf Exp $ +/* $Id: kthread.c,v 1.58 2004/11/10 02:50:59 ion Exp $ * * FILE: ntoskrnl/ke/kthread.c * PURPOSE: Microkernel thread support @@ -249,27 +249,7 @@ KeInitializeThread(PKPROCESS Process, PKTHREAD Thread, BOOLEAN First) Thread->PriorityDecrement = 0; Thread->Quantum = Process->ThreadQuantum; memset(Thread->WaitBlock, 0, sizeof(KWAIT_BLOCK)*4); - Thread->LegoData = 0; - - /* - * FIXME: Why this? - */ -// Thread->KernelApcDisable = 1; -/* -It may be correct to have regular kmode APC disabled -until the thread has been fully created, BUT the problem is: they are -currently never enabled again! So until somone figures out how -this really work, I'm setting regular kmode APC's intially enabled. --Gunnar - -UPDATE: After enabling regular kmode APC's I have experienced random -crashes. I'm disabling it again, until we fix the APC implementation... --Gunnar -*/ - - Thread->KernelApcDisable = -1; - - + Thread->LegoData = 0; Thread->UserAffinity = Process->Affinity; Thread->SystemAffinityActive = 0; Thread->PowerState = 0; @@ -298,15 +278,11 @@ crashes. I'm disabling it again, until we fix the APC implementation... Thread->KernelTime = 0; Thread->UserTime = 0; memset(&Thread->SavedApcState, 0, sizeof(KAPC_STATE)); - - /* FIXME: is this correct? */ - Thread->Alertable = 1; - + Thread->ApcStateIndex = OriginalApcEnvironment; - Thread->ApcQueueable = TRUE; - Thread->AutoAlignment = Process->AutoAlignment; + KeInitializeApc(&Thread->SuspendApc, Thread, OriginalApcEnvironment, @@ -316,6 +292,7 @@ crashes. I'm disabling it again, until we fix the APC implementation... KernelMode, NULL); KeInitializeSemaphore(&Thread->SuspendSemaphore, 0, 128); + InsertTailList(&Process->ThreadListHead, &Thread->ThreadListEntry); Thread->FreezeCount = 0; diff --git a/reactos/ntoskrnl/ke/wait.c b/reactos/ntoskrnl/ke/wait.c index 141a5193321..7d0bae8f220 100644 --- a/reactos/ntoskrnl/ke/wait.c +++ b/reactos/ntoskrnl/ke/wait.c @@ -546,7 +546,7 @@ KeWaitForMultipleObjects(ULONG Count, * If we are going to wait alertably and a user apc is pending * then return */ - if (Alertable && KiTestAlert()) + if (Alertable && KeTestAlertThread(KeGetPreviousMode())) { KeReleaseDispatcherDatabaseLock(OldIrql); return (STATUS_USER_APC); diff --git a/reactos/ntoskrnl/mm/i386/pfault.c b/reactos/ntoskrnl/mm/i386/pfault.c index ce6281d5fdf..dc868c9b7e0 100644 --- a/reactos/ntoskrnl/mm/i386/pfault.c +++ b/reactos/ntoskrnl/mm/i386/pfault.c @@ -65,10 +65,10 @@ NTSTATUS MmPageFault(ULONG Cs, } if (KeGetCurrentThread() != NULL && - KeGetCurrentThread()->Alerted[1] != 0 && - Cs != KERNEL_CS) + KeGetCurrentThread()->Alerted[UserMode] != 0 && + Cs != KERNEL_CS) { - KiDeliverNormalApc(); + KiDeliverApc(KernelMode, NULL, NULL); } if (!NT_SUCCESS(Status) && (Mode == KernelMode) && ((*Eip) >= (ULONG)MmSafeCopyFromUserUnsafeStart) && diff --git a/reactos/ntoskrnl/ps/create.c b/reactos/ntoskrnl/ps/create.c index fbed9ab4ae1..207f265bb77 100644 --- a/reactos/ntoskrnl/ps/create.c +++ b/reactos/ntoskrnl/ps/create.c @@ -1,4 +1,4 @@ -/* $Id: create.c,v 1.84 2004/10/24 20:37:27 weiden Exp $ +/* $Id: create.c,v 1.85 2004/11/10 02:51:00 ion Exp $ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel @@ -758,13 +758,15 @@ NtCreateThread(OUT PHANDLE ThreadHandle, LdrInitApcRundownRoutine, LdrpGetSystemDllEntryPoint(), UserMode, NULL); KeInsertQueueApc(LdrInitApc, NULL, NULL, IO_NO_INCREMENT); - - /* - * Start the thread running and force it to execute the APC(s) we just - * queued before it runs anything else in user-mode. + + /* + * The thread is non-alertable, so the APC we added did not set UserApcPending to TRUE. + * We must do this manually. Do NOT attempt to set the Thread to Alertable before the call, + * doing so is a blatant and erronous hack. */ - Thread->Tcb.Alertable = TRUE; - Thread->Tcb.Alerted[0] = 1; + Thread->Tcb.ApcState.UserApcPending = TRUE; + Thread->Tcb.Alerted[KernelMode] = TRUE; + PsUnblockThread(Thread, NULL); return(STATUS_SUCCESS); diff --git a/reactos/ntoskrnl/ps/process.c b/reactos/ntoskrnl/ps/process.c index c2e6b8ed53f..b7c058c2de5 100644 --- a/reactos/ntoskrnl/ps/process.c +++ b/reactos/ntoskrnl/ps/process.c @@ -1,4 +1,4 @@ -/* $Id: process.c,v 1.148 2004/10/31 21:22:06 navaraf Exp $ +/* $Id: process.c,v 1.149 2004/11/10 02:51:00 ion Exp $ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel @@ -51,6 +51,16 @@ typedef struct /* FUNCTIONS *****************************************************************/ +VOID +STDCALL +PsExitSpecialApc(PKAPC Apc, + PKNORMAL_ROUTINE *NormalRoutine, + PVOID *NormalContext, + PVOID *SystemArgument1, + PVOID *SystemArgument2) +{ +} + PEPROCESS PsGetNextProcess(PEPROCESS OldProcess) {