/* * @implemented */ BOOLEAN NTAPI KeSetTimerEx(IN OUT PKTIMER Timer, IN LARGE_INTEGER DueTime, IN LONG Period, IN PKDPC Dpc OPTIONAL) { KIRQL OldIrql; BOOLEAN Inserted; ULONG Hand = 0; BOOLEAN RequestInterrupt = FALSE; ASSERT_TIMER(Timer); ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); DPRINT("KeSetTimerEx(): Timer %p, DueTime %I64d, Period %d, Dpc %p\n", Timer, DueTime.QuadPart, Period, Dpc); /* Lock the Database and Raise IRQL */ OldIrql = KiAcquireDispatcherLock(); /* Check if it's inserted, and remove it if it is */ Inserted = Timer->Header.Inserted; if (Inserted) KxRemoveTreeTimer(Timer); /* Set Default Timer Data */ Timer->Dpc = Dpc; Timer->Period = Period; if (!KiComputeDueTime(Timer, DueTime, &Hand)) { /* Signal the timer */ RequestInterrupt = KiSignalTimer(Timer); /* Release the dispatcher lock */ KiReleaseDispatcherLockFromDpcLevel(); /* Check if we need to do an interrupt */ if (RequestInterrupt) HalRequestSoftwareInterrupt(DISPATCH_LEVEL); } else { /* Insert the timer */ Timer->Header.SignalState = FALSE; KxInsertTimer(Timer, Hand); } /* Exit the dispatcher */ KiExitDispatcher(OldIrql); /* Return old state */ return Inserted; }
/* * @implemented */ LONG NTAPI KePulseEvent(IN PKEVENT Event, IN KPRIORITY Increment, IN BOOLEAN Wait) { KIRQL OldIrql; LONG PreviousState; PKTHREAD Thread; ASSERT_EVENT(Event); ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); /* Lock the Dispatcher Database */ OldIrql = KiAcquireDispatcherLock(); /* Save the Old State */ PreviousState = Event->Header.SignalState; /* Check if we are non-signaled and we have stuff in the Wait Queue */ if (!PreviousState && !IsListEmpty(&Event->Header.WaitListHead)) { /* Set the Event to Signaled */ Event->Header.SignalState = 1; /* Wake the Event */ KiWaitTest(&Event->Header, Increment); } /* Unsignal it */ Event->Header.SignalState = 0; /* Check what wait state was requested */ if (Wait == FALSE) { /* Wait not requested, release Dispatcher Database and return */ KiReleaseDispatcherLock(OldIrql); } else { /* Return Locked and with a Wait */ Thread = KeGetCurrentThread(); Thread->WaitNext = TRUE; Thread->WaitIrql = OldIrql; } /* Return the previous State */ return PreviousState; }
/* * @implemented */ VOID NTAPI KeInitializeMutant(IN PKMUTANT Mutant, IN BOOLEAN InitialOwner) { PKTHREAD CurrentThread; KIRQL OldIrql; /* Check if we have an initial owner */ if (InitialOwner) { /* We also need to associate a thread */ CurrentThread = KeGetCurrentThread(); Mutant->OwnerThread = CurrentThread; /* We're about to touch the Thread, so lock the Dispatcher */ OldIrql = KiAcquireDispatcherLock(); /* And insert it into its list */ InsertTailList(&CurrentThread->MutantListHead, &Mutant->MutantListEntry); /* Release Dispatcher Lock */ KiReleaseDispatcherLock(OldIrql); } else { /* In this case, we don't have an owner yet */ Mutant->OwnerThread = NULL; } /* Now we set up the Dispatcher Header */ Mutant->Header.Type = MutantObject; Mutant->Header.Size = sizeof(KMUTANT) / sizeof(ULONG); Mutant->Header.SignalState = InitialOwner ? 0 : 1; InitializeListHead(&(Mutant->Header.WaitListHead)); /* Initialize the default data */ Mutant->Abandoned = FALSE; Mutant->ApcDisable = 0; }
/* * @implemented */ LONG NTAPI KeResetEvent(IN PKEVENT Event) { KIRQL OldIrql; LONG PreviousState; ASSERT_EVENT(Event); ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); /* Lock the Dispatcher Database */ OldIrql = KiAcquireDispatcherLock(); /* Save the Previous State */ PreviousState = Event->Header.SignalState; /* Set it to zero */ Event->Header.SignalState = 0; /* Release Dispatcher Database and return previous state */ KiReleaseDispatcherLock(OldIrql); return PreviousState; }
/* * @implemented */ BOOLEAN NTAPI KeCancelTimer(IN OUT PKTIMER Timer) { KIRQL OldIrql; BOOLEAN Inserted; ASSERT_TIMER(Timer); ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); DPRINT("KeCancelTimer(): Timer %p\n", Timer); /* Lock the Database and Raise IRQL */ OldIrql = KiAcquireDispatcherLock(); /* Check if it's inserted, and remove it if it is */ Inserted = Timer->Header.Inserted; if (Inserted) KxRemoveTreeTimer(Timer); /* Release Dispatcher Lock */ KiReleaseDispatcherLock(OldIrql); /* Return the old state */ return Inserted; }
/* * @implemented */ LONG NTAPI KeSetEvent(IN PKEVENT Event, IN KPRIORITY Increment, IN BOOLEAN Wait) { KIRQL OldIrql; LONG PreviousState; PKTHREAD Thread; ASSERT_EVENT(Event); ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); /* * Check if this is an signaled notification event without an upcoming wait. * In this case, we can immediately return TRUE, without locking. */ if ((Event->Header.Type == EventNotificationObject) && (Event->Header.SignalState == 1) && !(Wait)) { /* Return the signal state (TRUE/Signalled) */ return TRUE; } /* Lock the Dispathcer Database */ OldIrql = KiAcquireDispatcherLock(); /* Save the Previous State */ PreviousState = Event->Header.SignalState; /* Set the Event to Signaled */ Event->Header.SignalState = 1; /* Check if the event just became signaled now, and it has waiters */ if (!(PreviousState) && !(IsListEmpty(&Event->Header.WaitListHead))) { /* Check the type of event */ if (Event->Header.Type == EventNotificationObject) { /* Unwait the thread */ KxUnwaitThread(&Event->Header, Increment); } else { /* Otherwise unwait the thread and unsignal the event */ KxUnwaitThreadForEvent(Event, Increment); } } /* Check what wait state was requested */ if (!Wait) { /* Wait not requested, release Dispatcher Database and return */ KiReleaseDispatcherLock(OldIrql); } else { /* Return Locked and with a Wait */ Thread = KeGetCurrentThread(); Thread->WaitNext = TRUE; Thread->WaitIrql = OldIrql; } /* Return the previous State */ return PreviousState; }
/* * @implemented */ VOID NTAPI KeSetEventBoostPriority(IN PKEVENT Event, IN PKTHREAD *WaitingThread OPTIONAL) { KIRQL OldIrql; PKWAIT_BLOCK WaitBlock; PKTHREAD Thread = KeGetCurrentThread(), WaitThread; ASSERT(Event->Header.Type == EventSynchronizationObject); ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); /* Acquire Dispatcher Database Lock */ OldIrql = KiAcquireDispatcherLock(); /* Check if the list is empty */ if (IsListEmpty(&Event->Header.WaitListHead)) { /* Set the Event to Signaled */ Event->Header.SignalState = 1; /* Return */ KiReleaseDispatcherLock(OldIrql); return; } /* Get the Wait Block */ WaitBlock = CONTAINING_RECORD(Event->Header.WaitListHead.Flink, KWAIT_BLOCK,
/*++ * @name KiInsertQueueApc * * The KiInsertQueueApc routine queues a APC for execution when the right * scheduler environment exists. * * @param Apc * Pointer to an initialized control object of type APC for which the * caller provides the storage. * * @param PriorityBoost * Priority Boost to apply to the Thread. * * @return None * * @remarks The APC will execute at APC_LEVEL for the KernelRoutine registered, * and at PASSIVE_LEVEL for the NormalRoutine registered. * * Callers of this routine must have locked the dipatcher database. * *--*/ VOID FASTCALL KiInsertQueueApc(IN PKAPC Apc, IN KPRIORITY PriorityBoost) { PKTHREAD Thread = Apc->Thread; PKAPC_STATE ApcState; KPROCESSOR_MODE ApcMode; PLIST_ENTRY ListHead, NextEntry; PKAPC QueuedApc; PKGATE Gate; NTSTATUS Status; BOOLEAN RequestInterrupt = FALSE; /* * Check if the caller wanted this APC to use the thread's environment at * insertion time. */ if (Apc->ApcStateIndex == InsertApcEnvironment) { /* Copy it over */ Apc->ApcStateIndex = Thread->ApcStateIndex; } /* Get the APC State for this Index, and the mode too */ ApcState = Thread->ApcStatePointer[(UCHAR)Apc->ApcStateIndex]; ApcMode = Apc->ApcMode; /* The APC must be "inserted" already */ ASSERT(Apc->Inserted == TRUE); /* 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->NormalRoutine) { /* Normal APC; is it the Thread Termination APC? */ if ((ApcMode != KernelMode) && (Apc->KernelRoutine == PsExitSpecialApc)) { /* Set User APC pending to true */ Thread->ApcState.UserApcPending = TRUE; /* Insert it at the top of the list */ InsertHeadList(&ApcState->ApcListHead[ApcMode], &Apc->ApcListEntry); } else { /* Regular user or kernel Normal APC */ InsertTailList(&ApcState->ApcListHead[ApcMode], &Apc->ApcListEntry); } } else { /* Special APC, find the last one in the list */ ListHead = &ApcState->ApcListHead[ApcMode]; NextEntry = ListHead->Blink; while (NextEntry != ListHead) { /* Get the APC */ QueuedApc = CONTAINING_RECORD(NextEntry, KAPC, ApcListEntry); /* Is this a No-Normal APC? If so, break */ if (!QueuedApc->NormalRoutine) break; /* Move to the previous APC in the Queue */ NextEntry = NextEntry->Blink; } /* Insert us here */ InsertHeadList(NextEntry, &Apc->ApcListEntry); } /* Now check if the Apc State Indexes match */ if (Thread->ApcStateIndex == Apc->ApcStateIndex) { /* Check that the thread matches */ if (Thread == KeGetCurrentThread()) { /* Sanity check */ ASSERT(Thread->State == Running); /* Check if this is kernel mode */ if (ApcMode == KernelMode) { /* All valid, a Kernel APC is pending now */ Thread->ApcState.KernelApcPending = TRUE; /* Check if Special APCs are disabled */ if (!Thread->SpecialApcDisable) { /* They're not, so request the interrupt */ HalRequestSoftwareInterrupt(APC_LEVEL); } } } else { /* Acquire the dispatcher lock */ KiAcquireDispatcherLock(); /* Check if this is a kernel-mode APC */ if (ApcMode == KernelMode) { /* Kernel-mode APC, set us pending */ Thread->ApcState.KernelApcPending = TRUE; /* Are we currently running? */ if (Thread->State == Running) { /* The thread is running, so remember to send a request */ RequestInterrupt = TRUE; } else if ((Thread->State == Waiting) && (Thread->WaitIrql == PASSIVE_LEVEL) && !(Thread->SpecialApcDisable) && (!(Apc->NormalRoutine) || (!(Thread->KernelApcDisable) && !(Thread->ApcState.KernelApcInProgress)))) { /* We'll unwait with this status */ Status = STATUS_KERNEL_APC; /* Wake up the thread */ KiUnwaitThread(Thread, Status, PriorityBoost); } else if (Thread->State == GateWait) { /* Lock the thread */ KiAcquireThreadLock(Thread); /* Essentially do the same check as above */ if ((Thread->State == GateWait) && (Thread->WaitIrql == PASSIVE_LEVEL) && !(Thread->SpecialApcDisable) && (!(Apc->NormalRoutine) || (!(Thread->KernelApcDisable) && !(Thread->ApcState.KernelApcInProgress)))) { /* We were in a gate wait. Handle this. */ DPRINT1("A thread was in a gate wait\n"); /* Get the gate */ Gate = Thread->GateObject; /* Lock the gate */ KiAcquireDispatcherObject(&Gate->Header); /* Remove it from the waiters list */ RemoveEntryList(&Thread->WaitBlock[0].WaitListEntry); /* Unlock the gate */ KiReleaseDispatcherObject(&Gate->Header); /* Increase the queue counter if needed */ if (Thread->Queue) Thread->Queue->CurrentCount++; /* Put into deferred ready list with this status */ Thread->WaitStatus = STATUS_KERNEL_APC; KiInsertDeferredReadyList(Thread); } /* Release the thread lock */ KiReleaseThreadLock(Thread); } } else if ((Thread->State == Waiting) && (Thread->WaitMode == UserMode) && ((Thread->Alertable) || (Thread->ApcState.UserApcPending))) { /* Set user-mode APC pending */ Thread->ApcState.UserApcPending = TRUE; Status = STATUS_USER_APC; /* Wake up the thread */ KiUnwaitThread(Thread, Status, PriorityBoost); } /* Release dispatcher lock */ KiReleaseDispatcherLockFromDpcLevel(); /* Check if an interrupt was requested */ KiRequestApcInterrupt(RequestInterrupt, Thread->NextProcessor); } } }
/* * @implemented */ BOOLEAN NTAPI KeDisconnectInterrupt(IN PKINTERRUPT Interrupt) { KIRQL OldIrql, Irql; ULONG Vector; DISPATCH_INFO Dispatch; PKINTERRUPT NextInterrupt; BOOLEAN State; /* Set the affinity */ KeSetSystemAffinityThread(1 << Interrupt->Number); /* Lock the dispatcher */ OldIrql = KiAcquireDispatcherLock(); /* Check if it's actually connected */ State = Interrupt->Connected; if (State) { /* Get the vector and IRQL */ Irql = Interrupt->Irql; Vector = Interrupt->Vector; /* Get vector dispatch data */ KiGetVectorDispatch(Vector, &Dispatch); /* Check if it was chained */ if (Dispatch.Type == ChainConnect) { /* Check if the top-level interrupt is being removed */ ASSERT(Irql <= SYNCH_LEVEL); if (Interrupt == Dispatch.Interrupt) { /* Get the next one */ Dispatch.Interrupt = CONTAINING_RECORD(Dispatch.Interrupt-> InterruptListEntry.Flink, KINTERRUPT, InterruptListEntry); /* Reconnect it */ KiConnectVectorToInterrupt(Dispatch.Interrupt, ChainConnect); } /* Remove it */ RemoveEntryList(&Interrupt->InterruptListEntry); /* Get the next one */ NextInterrupt = CONTAINING_RECORD(Dispatch.Interrupt-> InterruptListEntry.Flink, KINTERRUPT, InterruptListEntry); /* Check if this is the only one left */ if (Dispatch.Interrupt == NextInterrupt) { /* Connect it in non-chained mode */ KiConnectVectorToInterrupt(Dispatch.Interrupt, NormalConnect); } } else { /* Only one left, disable and remove it */ HalDisableSystemInterrupt(Interrupt->Vector, Irql); KiConnectVectorToInterrupt(Interrupt, NoConnect); } /* Disconnect it */ Interrupt->Connected = FALSE; } /* Unlock the dispatcher and revert affinity */ KiReleaseDispatcherLock(OldIrql); KeRevertToUserAffinityThread(); /* Return to caller */ return State; }
/* * @implemented */ BOOLEAN NTAPI KeConnectInterrupt(IN PKINTERRUPT Interrupt) { BOOLEAN Connected, Error, Status; KIRQL Irql, OldIrql; UCHAR Number; ULONG Vector; DISPATCH_INFO Dispatch; /* Get data from interrupt */ Number = Interrupt->Number; Vector = Interrupt->Vector; Irql = Interrupt->Irql; /* Validate the settings */ if ((Irql > HIGH_LEVEL) || (Number >= KeNumberProcessors) || (Interrupt->SynchronizeIrql < Irql) || (Interrupt->FloatingSave)) { return FALSE; } /* Set defaults */ Connected = FALSE; Error = FALSE; /* Set the system affinity and acquire the dispatcher lock */ KeSetSystemAffinityThread(1 << Number); OldIrql = KiAcquireDispatcherLock(); /* Check if it's already been connected */ if (!Interrupt->Connected) { /* Get vector dispatching information */ KiGetVectorDispatch(Vector, &Dispatch); /* Check if the vector is already connected */ if (Dispatch.Type == NoConnect) { /* Do the connection */ Interrupt->Connected = Connected = TRUE; /* Initialize the list */ InitializeListHead(&Interrupt->InterruptListEntry); /* Connect and enable the interrupt */ KiConnectVectorToInterrupt(Interrupt, NormalConnect); Status = HalEnableSystemInterrupt(Vector, Irql, Interrupt->Mode); if (!Status) Error = TRUE; } else if ((Dispatch.Type != UnknownConnect) && (Interrupt->ShareVector) && (Dispatch.Interrupt->ShareVector) && (Dispatch.Interrupt->Mode == Interrupt->Mode)) { /* The vector is shared and the interrupts are compatible */ Interrupt->Connected = Connected = TRUE; /* FIXME */ // ASSERT(Irql <= SYNCH_LEVEL); /* Check if this is the first chain */ if (Dispatch.Type != ChainConnect) { /* This is not supported */ ASSERT(Dispatch.Interrupt->Mode != Latched); /* Setup the chainned handler */ KiConnectVectorToInterrupt(Dispatch.Interrupt, ChainConnect); } /* Insert into the interrupt list */ InsertTailList(&Dispatch.Interrupt->InterruptListEntry, &Interrupt->InterruptListEntry); } } /* Unlock the dispatcher and revert affinity */ KiReleaseDispatcherLock(OldIrql); KeRevertToUserAffinityThread(); /* Check if we failed while trying to connect */ if ((Connected) && (Error)) { DPRINT1("HalEnableSystemInterrupt failed\n"); KeDisconnectInterrupt(Interrupt); Connected = FALSE; } /* Return to caller */ return Connected; }
VOID NTAPI KiTimerExpiration(IN PKDPC Dpc, IN PVOID DeferredContext, IN PVOID SystemArgument1, IN PVOID SystemArgument2) { ULARGE_INTEGER SystemTime, InterruptTime; LARGE_INTEGER Interval; LONG Limit, Index, i; ULONG Timers, ActiveTimers, DpcCalls; PLIST_ENTRY ListHead, NextEntry; KIRQL OldIrql; PKTIMER Timer; PKDPC TimerDpc; ULONG Period; DPC_QUEUE_ENTRY DpcEntry[MAX_TIMER_DPCS]; PKSPIN_LOCK_QUEUE LockQueue; #ifdef CONFIG_SMP PKPRCB Prcb = KeGetCurrentPrcb(); #endif /* Disable interrupts */ _disable(); /* Query system and interrupt time */ KeQuerySystemTime((PLARGE_INTEGER)&SystemTime); InterruptTime.QuadPart = KeQueryInterruptTime(); Limit = KeTickCount.LowPart; /* Bring interrupts back */ _enable(); /* Get the index of the timer and normalize it */ Index = PtrToLong(SystemArgument1); if ((Limit - Index) >= TIMER_TABLE_SIZE) { /* Normalize it */ Limit = Index + TIMER_TABLE_SIZE - 1; } /* Setup index and actual limit */ Index--; Limit &= (TIMER_TABLE_SIZE - 1); /* Setup accounting data */ DpcCalls = 0; Timers = 24; ActiveTimers = 4; /* Lock the Database and Raise IRQL */ OldIrql = KiAcquireDispatcherLock(); /* Start expiration loop */ do { /* Get the current index */ Index = (Index + 1) & (TIMER_TABLE_SIZE - 1); /* Get list pointers and loop the list */ ListHead = &KiTimerTableListHead[Index].Entry; while (ListHead != ListHead->Flink) { /* Lock the timer and go to the next entry */ LockQueue = KiAcquireTimerLock(Index); NextEntry = ListHead->Flink; /* Get the current timer and check its due time */ Timers--; Timer = CONTAINING_RECORD(NextEntry, KTIMER, TimerListEntry); if ((NextEntry != ListHead) && (Timer->DueTime.QuadPart <= InterruptTime.QuadPart)) { /* It's expired, remove it */ ActiveTimers--; KiRemoveEntryTimer(Timer); /* Make it non-inserted, unlock it, and signal it */ Timer->Header.Inserted = FALSE; KiReleaseTimerLock(LockQueue); Timer->Header.SignalState = 1; /* Get the DPC and period */ TimerDpc = Timer->Dpc; Period = Timer->Period; /* Check if there's any waiters */ if (!IsListEmpty(&Timer->Header.WaitListHead)) { /* Check the type of event */ if (Timer->Header.Type == TimerNotificationObject) { /* Unwait the thread */ KxUnwaitThread(&Timer->Header, IO_NO_INCREMENT); } else { /* Otherwise unwait the thread and signal the timer */ KxUnwaitThreadForEvent((PKEVENT)Timer, IO_NO_INCREMENT); } } /* Check if we have a period */ if (Period) { /* Calculate the interval and insert the timer */ Interval.QuadPart = Int32x32To64(Period, -10000); while (!KiInsertTreeTimer(Timer, Interval)); } /* Check if we have a DPC */ if (TimerDpc) { #ifdef CONFIG_SMP /* * If the DPC is targeted to another processor, * then insert it into that processor's DPC queue * instead of delivering it now. * If the DPC is a threaded DPC, and the current CPU * has threaded DPCs enabled (KiExecuteDpc is actively parsing DPCs), * then also insert it into the DPC queue for threaded delivery, * instead of doing it here. */ if (((TimerDpc->Number >= MAXIMUM_PROCESSORS) && ((TimerDpc->Number - MAXIMUM_PROCESSORS) != Prcb->Number)) || ((TimerDpc->Type == ThreadedDpcObject) && (Prcb->ThreadDpcEnable))) { /* Queue it */ KeInsertQueueDpc(TimerDpc, UlongToPtr(SystemTime.LowPart), UlongToPtr(SystemTime.HighPart)); } else #endif { /* Setup the DPC Entry */ DpcEntry[DpcCalls].Dpc = TimerDpc; DpcEntry[DpcCalls].Routine = TimerDpc->DeferredRoutine; DpcEntry[DpcCalls].Context = TimerDpc->DeferredContext; DpcCalls++; ASSERT(DpcCalls < MAX_TIMER_DPCS); } } /* Check if we're done processing */ if (!(ActiveTimers) || !(Timers)) { /* Release the dispatcher while doing DPCs */ KiReleaseDispatcherLock(DISPATCH_LEVEL); /* Start looping all DPC Entries */ for (i = 0; DpcCalls; DpcCalls--, i++) { /* Call the DPC */ DpcEntry[i].Routine(DpcEntry[i].Dpc, DpcEntry[i].Context, UlongToPtr(SystemTime.LowPart), UlongToPtr(SystemTime.HighPart)); } /* Reset accounting */ Timers = 24; ActiveTimers = 4; /* Lock the dispatcher database */ KiAcquireDispatcherLock(); } } else { /* Check if the timer list is empty */ if (NextEntry != ListHead) { /* Sanity check */ ASSERT(KiTimerTableListHead[Index].Time.QuadPart <= Timer->DueTime.QuadPart); /* Update the time */ _disable(); KiTimerTableListHead[Index].Time.QuadPart = Timer->DueTime.QuadPart; _enable(); } /* Release the lock */ KiReleaseTimerLock(LockQueue); /* Check if we've scanned all the timers we could */ if (!Timers) { /* Release the dispatcher while doing DPCs */ KiReleaseDispatcherLock(DISPATCH_LEVEL); /* Start looping all DPC Entries */ for (i = 0; DpcCalls; DpcCalls--, i++) { /* Call the DPC */ DpcEntry[i].Routine(DpcEntry[i].Dpc, DpcEntry[i].Context, UlongToPtr(SystemTime.LowPart), UlongToPtr(SystemTime.HighPart)); } /* Reset accounting */ Timers = 24; ActiveTimers = 4; /* Lock the dispatcher database */ KiAcquireDispatcherLock(); } /* Done looping */ break; } } } while (Index != Limit); /* Verify the timer table, on debug builds */ if (KeNumberProcessors == 1) KiCheckTimerTable(InterruptTime); /* Check if we still have DPC entries */ if (DpcCalls) { /* Release the dispatcher while doing DPCs */ KiReleaseDispatcherLock(DISPATCH_LEVEL); /* Start looping all DPC Entries */ for (i = 0; DpcCalls; DpcCalls--, i++) { /* Call the DPC */ DpcEntry[i].Routine(DpcEntry[i].Dpc, DpcEntry[i].Context, UlongToPtr(SystemTime.LowPart), UlongToPtr(SystemTime.HighPart)); } /* Lower IRQL if we need to */ if (OldIrql != DISPATCH_LEVEL) KeLowerIrql(OldIrql); } else { /* Unlock the dispatcher */ KiReleaseDispatcherLock(OldIrql); } }
VOID NTAPI KeSetSystemTime(IN PLARGE_INTEGER NewTime, OUT PLARGE_INTEGER OldTime, IN BOOLEAN FixInterruptTime, IN PLARGE_INTEGER HalTime OPTIONAL) { TIME_FIELDS TimeFields; KIRQL OldIrql, OldIrql2; LARGE_INTEGER DeltaTime; PLIST_ENTRY ListHead, NextEntry; PKTIMER Timer; PKSPIN_LOCK_QUEUE LockQueue; LIST_ENTRY TempList, TempList2; ULONG Hand, i; /* Sanity checks */ ASSERT((NewTime->HighPart & 0xF0000000) == 0); ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); /* Check if this is for the HAL */ if (HalTime) RtlTimeToTimeFields(HalTime, &TimeFields); /* Set affinity to this CPU, lock the dispatcher, and raise IRQL */ KeSetSystemAffinityThread(1); OldIrql = KiAcquireDispatcherLock(); KeRaiseIrql(HIGH_LEVEL, &OldIrql2); /* Query the system time now */ KeQuerySystemTime(OldTime); /* Set the new system time (ordering of these operations is critical) */ SharedUserData->SystemTime.High2Time = NewTime->HighPart; SharedUserData->SystemTime.LowPart = NewTime->LowPart; SharedUserData->SystemTime.High1Time = NewTime->HighPart; /* Check if this was for the HAL and set the RTC time */ if (HalTime) ExCmosClockIsSane = HalSetRealTimeClock(&TimeFields); /* Calculate the difference between the new and the old time */ DeltaTime.QuadPart = NewTime->QuadPart - OldTime->QuadPart; /* Update system boot time */ KeBootTime.QuadPart += DeltaTime.QuadPart; KeBootTimeBias = KeBootTimeBias + DeltaTime.QuadPart; /* Lower IRQL back */ KeLowerIrql(OldIrql2); /* Check if we need to adjust interrupt time */ if (FixInterruptTime) ASSERT(FALSE); /* Setup a temporary list of absolute timers */ InitializeListHead(&TempList); /* Loop current timers */ for (i = 0; i < TIMER_TABLE_SIZE; i++) { /* Loop the entries in this table and lock the timers */ ListHead = &KiTimerTableListHead[i].Entry; LockQueue = KiAcquireTimerLock(i); NextEntry = ListHead->Flink; while (NextEntry != ListHead) { /* Get the timer */ Timer = CONTAINING_RECORD(NextEntry, KTIMER, TimerListEntry); NextEntry = NextEntry->Flink; /* Is it absolute? */ if (Timer->Header.Absolute) { /* Remove it from the timer list */ KiRemoveEntryTimer(Timer); /* Insert it into our temporary list */ InsertTailList(&TempList, &Timer->TimerListEntry); } } /* Release the lock */ KiReleaseTimerLock(LockQueue); } /* Setup a temporary list of expired timers */ InitializeListHead(&TempList2); /* Loop absolute timers */ while (TempList.Flink != &TempList) { /* Get the timer */ Timer = CONTAINING_RECORD(TempList.Flink, KTIMER, TimerListEntry); RemoveEntryList(&Timer->TimerListEntry); /* Update the due time and handle */ Timer->DueTime.QuadPart -= DeltaTime.QuadPart; Hand = KiComputeTimerTableIndex(Timer->DueTime.QuadPart); Timer->Header.Hand = (UCHAR)Hand; /* Lock the timer and re-insert it */ LockQueue = KiAcquireTimerLock(Hand); if (KiInsertTimerTable(Timer, Hand)) { /* Remove it from the timer list */ KiRemoveEntryTimer(Timer); /* Insert it into our temporary list */ InsertTailList(&TempList2, &Timer->TimerListEntry); } /* Release the lock */ KiReleaseTimerLock(LockQueue); } /* Process expired timers. This releases the dispatcher lock. */ KiTimerListExpire(&TempList2, OldIrql); /* Revert affinity */ KeRevertToUserAffinityThread(); }
/* * @implemented */ LONG NTAPI KeReleaseMutant(IN PKMUTANT Mutant, IN KPRIORITY Increment, IN BOOLEAN Abandon, IN BOOLEAN Wait) { KIRQL OldIrql; LONG PreviousState; PKTHREAD CurrentThread = KeGetCurrentThread(); BOOLEAN EnableApc = FALSE; ASSERT_MUTANT(Mutant); ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); /* Lock the Dispatcher Database */ OldIrql = KiAcquireDispatcherLock(); /* Save the Previous State */ PreviousState = Mutant->Header.SignalState; /* Check if it is to be abandonned */ if (Abandon == FALSE) { /* Make sure that the Owner Thread is the current Thread */ if (Mutant->OwnerThread != CurrentThread) { /* Release the lock */ KiReleaseDispatcherLock(OldIrql); /* Raise an exception */ ExRaiseStatus(Mutant->Abandoned ? STATUS_ABANDONED : STATUS_MUTANT_NOT_OWNED); } /* If the thread owns it, then increase the signal state */ Mutant->Header.SignalState++; } else { /* It's going to be abandonned */ Mutant->Header.SignalState = 1; Mutant->Abandoned = TRUE; } /* Check if the signal state is only single */ if (Mutant->Header.SignalState == 1) { /* Check if it's below 0 now */ if (PreviousState <= 0) { /* Remove the mutant from the list */ RemoveEntryList(&Mutant->MutantListEntry); /* Save if we need to re-enable APCs */ EnableApc = Mutant->ApcDisable; } /* Remove the Owning Thread and wake it */ Mutant->OwnerThread = NULL; /* Check if the Wait List isn't empty */ if (!IsListEmpty(&Mutant->Header.WaitListHead)) { /* Wake the Mutant */ KiWaitTest(&Mutant->Header, Increment); } } /* Check if the caller wants to wait after this release */ if (Wait == FALSE) { /* Release the Lock */ KiReleaseDispatcherLock(OldIrql); } else { /* Set a wait */ CurrentThread->WaitNext = TRUE; CurrentThread->WaitIrql = OldIrql; } /* Check if we need to re-enable APCs */ if (EnableApc) KeLeaveCriticalRegion(); /* Return the previous state */ return PreviousState; }