Esempio n. 1
0
BOOLEAN
KeSetAutoAlignmentThread (
    IN PKTHREAD Thread,
    IN BOOLEAN Enable
    )

/*++

Routine Description:

    This function sets the data alignment handling mode for the specified
    thread and returns the previous data alignment handling mode.

Arguments:

    Thread  - Supplies a pointer to a dispatcher object of type thread.

    Enable - Supplies a boolean value that determines the handling of data
        alignment exceptions for the thread. A value of TRUE causes all
        data alignment exceptions to be automatically handled by the kernel.
        A value of FALSE causes all data alignment exceptions to be actually
        raised as exceptions.

Return Value:

    A value of TRUE is returned if data alignment exceptions were
    previously automatically handled by the kernel. Otherwise, a value
    of FALSE is returned.

--*/

{

    KIRQL OldIrql;
    BOOLEAN Previous;

    ASSERT_THREAD(Thread);

    //
    // Raise IRQL to dispatcher level and lock dispatcher database.
    //

    KiLockDispatcherDatabase(&OldIrql);

    //
    // Capture the previous data alignment handling mode and set the
    // specified data alignment mode.
    //

    Previous = Thread->AutoAlignment;
    Thread->AutoAlignment = Enable;

    //
    // Unlock dispatcher database, lower IRQL to its previous value, and
    // return the previous data alignment mode.
    //

    KiUnlockDispatcherDatabase(OldIrql);
    return Previous;
}
Esempio n. 2
0
VOID
ExpCheckForWorker (
    IN PVOID p,
    IN SIZE_T Size
    )

{
    KIRQL OldIrql;
    PLIST_ENTRY Entry;
    PCHAR BeginBlock;
    PCHAR EndBlock;
    WORK_QUEUE_TYPE wqt;

    BeginBlock = (PCHAR)p;
    EndBlock = (PCHAR)p + Size;

    KiLockDispatcherDatabase (&OldIrql);

    for (wqt = CriticalWorkQueue; wqt < MaximumWorkQueue; wqt += 1) {
        for (Entry = (PLIST_ENTRY) ExWorkerQueue[wqt].WorkerQueue.EntryListHead.Flink;
             Entry && (Entry != (PLIST_ENTRY) &ExWorkerQueue[wqt].WorkerQueue.EntryListHead);
             Entry = Entry->Flink) {
           if (((PCHAR) Entry >= BeginBlock) && ((PCHAR) Entry < EndBlock)) {
              KeBugCheckEx(WORKER_INVALID,
                           0x0,
                           (ULONG_PTR)Entry,
                           (ULONG_PTR)BeginBlock,
                           (ULONG_PTR)EndBlock);

           }
        }
    }
    KiUnlockDispatcherDatabase (OldIrql);
}
Esempio n. 3
0
LONG
KeResetEvent (
    IN PRKEVENT Event
    )

/*++

Routine Description:

    This function resets the signal state of an event object to
    Not-Signaled. The previous state of the event object is returned
    as the function value.

Arguments:

    Event - Supplies a pointer to a dispatcher object of type event.

Return Value:

    The previous signal state of the event object.

--*/

{

    KIRQL OldIrql;
    LONG OldState;

    ASSERT_EVENT(Event);
    ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);

    //
    // Raise IRQL to dispatcher level and lock dispatcher database.
    //

    KiLockDispatcherDatabase(&OldIrql);

    //
    // Capture the current signal state of event object and then reset
    // the state of the event object to Not-Signaled.
    //

    OldState = Event->Header.SignalState;
    Event->Header.SignalState = 0;

    //
    // Unlock the dispatcher database and lower IRQL to its previous
    // value.

    KiUnlockDispatcherDatabase(OldIrql);

    //
    // Return previous signal state of event object.
    //

    return OldState;
}
Esempio n. 4
0
VOID
KeAttachSessionSpace(
    PREGION_MAP_INFO SessionMapInfo
    )
/*++

 Routine Description:

    This routine attaches a session map info to the current process.

 Arguments: 

    SessionMapInfo - Supplies a session map info to be attached.

 Return Value:

    None.

 Environment:

    Kernel mode.

--*/
{
    KIRQL OldIrql;
    PKTHREAD Thread;
    PKPROCESS Process;

    Thread = KeGetCurrentThread();
    Process = Thread->ApcState.Process;

    //
    // Raise IRQL to dispatcher level and lock the dispatcher database.
    //

    KiLockDispatcherDatabase(&OldIrql);

    ASSERT(SessionMapInfo != NULL);

    //
    // Attach the given session map
    //

    Process->SessionMapInfo = SessionMapInfo;

    KiSyncNewRegionId(&Process->ProcessRegion, SessionMapInfo);

    //
    // unlock the dispatcher database
    //

    KiUnlockDispatcherDatabase(OldIrql);
    
}
Esempio n. 5
0
VOID
KeDisableSessionSharing(
    PREGION_MAP_INFO SessionMapInfo
    )
/*++

 Routine Description:

    This routine disables session sharing by the other process.

 Arguments: 

    SessionMapInfo - Supplies a session map info to be disabled 
           for sharing.

 Return Value:

    None.

 Environment:

    Kernel mode.

--*/
{
    PKPROCESS Process;
    PKTHREAD Thread;
    KIRQL OldIrql;

    Thread = KeGetCurrentThread();
    Process = Thread->ApcState.Process;

    //
    // Raise IRQL to dispatcher level and lock the dispatcher database.
    //

    KiLockDispatcherDatabase(&OldIrql);

    Process->SessionRegion.RegionId = SessionMapInfo->RegionId;
    Process->SessionRegion.SequenceNumber = SessionMapInfo->SequenceNumber;
    Process->SessionMapInfo = &Process->SessionRegion;

    //
    // unlock the dispatcher database
    //

    KiUnlockDispatcherDatabase(OldIrql);
}
Esempio n. 6
0
VOID
KeBoostCurrentThread(
    VOID
    )

/*++

Routine Description:

    This function boosts the priority of the current thread for one quantum,
    then reduce the thread priority to the base priority of the thread.

Arguments:

    None.

Return Value:

    None.

--*/

{

    KIRQL OldIrql;
    PKTHREAD Thread;

    //
    // Get current thread address, raise IRQL to synchronization level, and
    // lock the dispatcher database
    //

    Thread = KeGetCurrentThread();

redoboost:
    KiLockDispatcherDatabase(&OldIrql);

    //
    // If a priority boost is not already active for the current thread
    // and the thread priority is less than 14, then boost the thread
    // priority to 14 and give the thread a large quantum. Otherwise,
    // if a priority boost is active, then decrement the round trip
    // count. If the count goes to zero, then release the dispatcher
    // database lock, lower the thread priority to the base priority,
    // and then attempt to boost the priority again. This will give
    // other threads a chance to run. If the count does not reach zero,
    // then give the thread another large qunatum.
    //
    // If the thread priority is above 14, then no boost is applied.
    //

    if ((Thread->PriorityDecrement == 0) && (Thread->Priority < 14)) {
        Thread->PriorityDecrement = 14 - Thread->BasePriority;
        Thread->DecrementCount = ROUND_TRIP_DECREMENT_COUNT;
        Thread->Priority = 14;
        Thread->Quantum = Thread->ApcState.Process->ThreadQuantum * 2;

    } else if (Thread->PriorityDecrement != 0) {
        Thread->DecrementCount -= 1;
        if (Thread->DecrementCount == 0) {
            KiUnlockDispatcherDatabase(OldIrql);
            KeSetPriorityThread(Thread, Thread->BasePriority);
            goto redoboost;

        } else {
            Thread->Quantum = Thread->ApcState.Process->ThreadQuantum * 2;
        }
    }

    KiUnlockDispatcherDatabase(OldIrql);
    return;
}
Esempio n. 7
0
LONG
KeReleaseMutant (
    IN PRKMUTANT Mutant,
    IN KPRIORITY Increment,
    IN BOOLEAN Abandoned,
    IN BOOLEAN Wait
    )

/*++

Routine Description:

    This function releases a mutant object by incrementing the mutant
    count. If the resultant value is one, then an attempt is made to
    satisfy as many Waits as possible. The previous signal state of
    the mutant is returned as the function value. If the Abandoned
    parameter is TRUE, then the mutant object is released by settings
    the signal state to one.

Arguments:

    Mutant - Supplies a pointer to a dispatcher object of type mutant.

    Increment - Supplies the priority increment that is to be applied
        if setting the event causes a Wait to be satisfied.

    Abandoned - Supplies a boolean value that signifies whether the
        mutant object is being abandoned.

    Wait - Supplies a boolean value that signifies whether the call to
        KeReleaseMutant will be immediately followed by a call to one
        of the kernel Wait functions.

Return Value:

    The previous signal state of the mutant object.

--*/

{

    KIRQL OldIrql;
    LONG OldState;
    PRKTHREAD Thread;


    ASSERT_MUTANT(Mutant);
    ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);

    //
    // Raise IRQL to dispatcher level and lock dispatcher database.
    //

    KiLockDispatcherDatabase(&OldIrql);

    //
    // Capture the current signal state of the mutant object.
    //

    OldState = Mutant->Header.SignalState;

    //
    // If the Abandoned parameter is TRUE, then force the release of the
    // mutant object by setting its ownership count to one and setting its
    // abandoned state to TRUE. Otherwise increment mutant ownership count.
    // If the result count is one, then remove the mutant object from the
    // thread's owned mutant list, set the owner thread to NULL, and attempt
    // to satisfy a Wait for the mutant object if the mutant object wait
    // list is not empty.
    //

    Thread = KeGetCurrentThread();
    if (Abandoned != FALSE) {
        Mutant->Header.SignalState = 1;
        Mutant->Abandoned = TRUE;

    } else {

        //
        // If the Mutant object is not owned by the current thread, then
        // unlock the dispatcher data base and raise an exception. Otherwise
        // increment the ownership count.
        //

        if (Mutant->OwnerThread != Thread) {
            KiUnlockDispatcherDatabase(OldIrql);
            ExRaiseStatus(Mutant->Abandoned ?
                          STATUS_ABANDONED : STATUS_MUTANT_NOT_OWNED);
        }

        Mutant->Header.SignalState += 1;
    }

    if (Mutant->Header.SignalState == 1) {
        if (OldState <= 0) {
            RemoveEntryList(&Mutant->MutantListEntry);
            Thread->KernelApcDisable += Mutant->ApcDisable;
            if ((Thread->KernelApcDisable == 0) &&
                (IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode]) == FALSE)) {
                Thread->ApcState.KernelApcPending = TRUE;
                KiRequestSoftwareInterrupt(APC_LEVEL);
            }
        }

        Mutant->OwnerThread = (PKTHREAD)NULL;
        if (IsListEmpty(&Mutant->Header.WaitListHead) == FALSE) {
            KiWaitTest(Mutant, Increment);
        }
    }

    //
    // If the value of the Wait argument is TRUE, then return to
    // caller with IRQL raised and the dispatcher database locked.
    // Else release the dispatcher database lock and lower IRQL to
    // its previous value.
    //

    if (Wait != FALSE) {
        Thread->WaitNext = Wait;
        Thread->WaitIrql = OldIrql;

    } else {
        KiUnlockDispatcherDatabase(OldIrql);
    }

    //
    // Return previous signal state of mutant object.
    //

    return OldState;
}
Esempio n. 8
0
NTSTATUS
KeWaitForSingleObject (
    IN PVOID Object,
    IN KWAIT_REASON WaitReason,
    IN KPROCESSOR_MODE WaitMode,
    IN BOOLEAN Alertable,
    IN PLARGE_INTEGER Timeout OPTIONAL
    )

/*++

Routine Description:

    This function waits until the specified object attains a state of
    Signaled. An optional timeout can also be specified. If a timeout
    is not specified, then the wait will not be satisfied until the object
    attains a state of Signaled. If a timeout is specified, and the object
    has not attained a state of Signaled when the timeout expires, then
    the wait is automatically satisfied. If an explicit timeout value of
    zero is specified, then no wait will occur if the wait cannot be satisfied
    immediately. The wait can also be specified as alertable.

Arguments:

    Object - Supplies a pointer to a dispatcher object.

    WaitReason - Supplies the reason for the wait.

    WaitMode  - Supplies the processor mode in which the wait is to occur.

    Alertable - Supplies a boolean value that specifies whether the wait is
        alertable.

    Timeout - Supplies a pointer to an optional absolute of relative time over
        which the wait is to occur.

Return Value:

    The wait completion status. A value of STATUS_TIMEOUT is returned if a
    timeout occurred. A value of STATUS_SUCCESS is returned if the specified
    object satisfied the wait. A value of STATUS_ALERTED is returned if the
    wait was aborted to deliver an alert to the current thread. A value of
    STATUS_USER_APC is returned if the wait was aborted to deliver a user
    APC to the current thread.

--*/

{

    LARGE_INTEGER DueTime;
    LARGE_INTEGER NewTime;
    PRKTHREAD NextThread;
    PKMUTANT Objectx;
    PLARGE_INTEGER OriginalTime;
    PRKQUEUE Queue;
    PRKTHREAD Thread;
    PRKTIMER Timer;
    PKWAIT_BLOCK WaitBlock;
    NTSTATUS WaitStatus;
    PKWAIT_BLOCK WaitTimer;

    //
    // Collect call data.
    //

#if defined(_COLLECT_WAIT_SINGLE_CALLDATA_)

    RECORD_CALL_DATA(&KiWaitSingleCallData);

#endif

    //
    // If the dispatcher database lock is not already held, then set the wait
    // IRQL and lock the dispatcher database. Else set boolean wait variable
    // to FALSE.
    //

    Thread = KeGetCurrentThread();
    if (Thread->WaitNext) {
        Thread->WaitNext = FALSE;

    } else {
        KiLockDispatcherDatabase(&Thread->WaitIrql);
    }

    //
    // Start of wait loop.
    //
    // Note this loop is repeated if a kernel APC is delivered in the middle
    // of the wait or a kernel APC is pending on the first attempt through
    // the loop.
    //

    OriginalTime = Timeout;
    WaitBlock = &Thread->WaitBlock[0];
    do {

        //
        // Test to determine if a kernel APC is pending.
        //
        // If a kernel APC is pending and the previous IRQL was less than
        // APC_LEVEL, then a kernel APC was queued by another processor just
        // after IRQL was raised to DISPATCH_LEVEL, but before the dispatcher
        // database was locked.
        //
        // N.B. that this can only happen in a multiprocessor system.
        //

        if (Thread->ApcState.KernelApcPending && (Thread->WaitIrql < APC_LEVEL)) {

            //
            // Unlock the dispatcher database and lower IRQL to its previous
            // value. An APC interrupt will immediately occur which will result
            // in the delivery of the kernel APC if possible.
            //

            KiUnlockDispatcherDatabase(Thread->WaitIrql);

        } else {

            //
            // Test if the wait can be immediately satisfied.
            //

            Objectx = (PKMUTANT)Object;
            Thread->WaitStatus = (NTSTATUS)0;

            ASSERT(Objectx->Header.Type != QueueObject);

            //
            // If the object is a mutant object and the mutant object has been
            // recursively acquired MINLONG times, then raise an exception.
            // Otherwise if the signal state of the mutant object is greater
            // than zero, or the current thread is the owner of the mutant
            // object, then satisfy the wait.
            //

            if (Objectx->Header.Type == MutantObject) {
                if ((Objectx->Header.SignalState > 0) ||
                    (Thread == Objectx->OwnerThread)) {
                    if (Objectx->Header.SignalState != MINLONG) {
                        KiWaitSatisfyMutant(Objectx, Thread);
                        WaitStatus = (NTSTATUS)(Thread->WaitStatus);
                        goto NoWait;

                    } else {
                        KiUnlockDispatcherDatabase(Thread->WaitIrql);
                        ExRaiseStatus(STATUS_MUTANT_LIMIT_EXCEEDED);
                    }
                }

            //
            // If the signal state is greater than zero, then satisfy the wait.
            //

            } else if (Objectx->Header.SignalState > 0) {
                KiWaitSatisfyOther(Objectx);
                WaitStatus = (NTSTATUS)(0);
                goto NoWait;
            }

            //
            // Construct a wait block for the object.
            //

            Thread->WaitBlockList = WaitBlock;
            WaitBlock->Object = Object;
            WaitBlock->WaitKey = (CSHORT)(STATUS_SUCCESS);
            WaitBlock->WaitType = WaitAny;

            //
            // Test for alert pending.
            //

            TestForAlertPending(Alertable);

            //
            // The wait cannot be satisifed immediately. Check to determine if
            // a timeout value is specified.
            //

            if (ARGUMENT_PRESENT(Timeout)) {

                //
                // If the timeout value is zero, then return immediately without
                // waiting.
                //

                if (!(Timeout->LowPart | Timeout->HighPart)) {
                    WaitStatus = (NTSTATUS)(STATUS_TIMEOUT);
                    goto NoWait;
                }

                //
                // Initialize a wait block for the thread specific timer, insert
                // wait block in timer wait list, insert the timer in the timer
                // tree.
                //
                // N.B. The timer wait block is initialized when the respective
                //      thread is initialized. Thus the constant fields are not
                //      reinitialized. These include the wait object, wait key,
                //      wait type, and the wait list entry link pointers.
                //

                Timer = &Thread->Timer;
                WaitTimer = &Thread->WaitBlock[TIMER_WAIT_BLOCK];
                WaitBlock->NextWaitBlock = WaitTimer;
                Timer->Header.WaitListHead.Flink = &WaitTimer->WaitListEntry;
                Timer->Header.WaitListHead.Blink = &WaitTimer->WaitListEntry;
                WaitTimer->NextWaitBlock = WaitBlock;
                if (KiInsertTreeTimer(Timer, *Timeout) == FALSE) {
                    WaitStatus = (NTSTATUS)STATUS_TIMEOUT;
                    goto NoWait;
                }

                DueTime.QuadPart = Timer->DueTime.QuadPart;

            } else {
                WaitBlock->NextWaitBlock = WaitBlock;
            }

            //
            // Insert wait block in object wait list.
            //

            InsertTailList(&Objectx->Header.WaitListHead, &WaitBlock->WaitListEntry);

            //
            // If the current thread is processing a queue entry, then attempt
            // to activate another thread that is blocked on the queue object.
            //

            Queue = Thread->Queue;
            if (Queue != NULL) {
                KiActivateWaiterQueue(Queue);
            }

            //
            // Set the thread wait parameters, set the thread dispatcher state
            // to Waiting, and insert the thread in the wait list.
            //

            Thread->Alertable = Alertable;
            Thread->WaitMode = WaitMode;
            Thread->WaitReason = (UCHAR)WaitReason;
            Thread->WaitTime= KiQueryLowTickCount();
            Thread->State = Waiting;
            KiInsertWaitList(WaitMode, Thread);

            //
            // Switch context to selected thread.
            //
            // Control is returned at the original IRQL.
            //

            ASSERT(Thread->WaitIrql <= DISPATCH_LEVEL);

            WaitStatus = (NTSTATUS)KiSwapThread();

            //
            // If the thread was not awakened to deliver a kernel mode APC,
            // then return wait status.
            //

            if (WaitStatus != STATUS_KERNEL_APC) {
                return WaitStatus;
            }

            if (ARGUMENT_PRESENT(Timeout)) {

                //
                // Reduce the amount of time remaining before timeout occurs.
                //

                Timeout = KiComputeWaitInterval(OriginalTime,
                                                &DueTime,
                                                &NewTime);
            }
        }

        //
        // Raise IRQL to DISPATCH_LEVEL and lock the dispatcher database.
        //

        KiLockDispatcherDatabase(&Thread->WaitIrql);
    } while (TRUE);

    //
    // The thread is alerted or a user APC should be delivered. Unlock the
    // dispatcher database, lower IRQL to its previous value, and return
    // the wait status.
    //

    KiUnlockDispatcherDatabase(Thread->WaitIrql);
    return WaitStatus;

    //
    // The wait has been satisfied without actually waiting.
    //
    // If the thread priority that is less than time critical, then reduce
    // the thread quantum. If a quantum end occurs, then reduce the thread
    // priority.
    //

NoWait:
    KiAdjustQuantumThread(Thread);

    //
    // Unlock the dispatcher database, lower IRQL to its previous value, and
    // return the wait status.
    //

    KiUnlockDispatcherDatabase(Thread->WaitIrql);
    return WaitStatus;
}
Esempio n. 9
0
VOID
KeAttachProcess (
    IN PRKPROCESS Process
    )

/*++

Routine Description:

    This function attaches a thread to a target process' address space
    if, and only if, there is not already a process attached.

Arguments:

    Process - Supplies a pointer to a dispatcher object of type process.

Return Value:

    None.

--*/

{

    KIRQL OldIrql;
    PRKTHREAD Thread;

    ASSERT_PROCESS(Process);
    ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);

    //
    // Raise IRQL to dispatcher level and lock dispatcher database.
    //

    Thread = KeGetCurrentThread();
    KiLockDispatcherDatabase(&OldIrql);

    //
    // If the target process is the current process, then return immediately.
    // Otherwise, check whether there is a process address space attached or
    // the thread is executing a DPC. If either condition is true, then call
    // bug check. Otherwise, attach the target process.
    //

    if (Thread->ApcState.Process == Process) {
        KiUnlockDispatcherDatabase(OldIrql);

    } else if ((Thread->ApcStateIndex != 0) ||
               (KeIsExecutingDpc() != FALSE)) {
        KeBugCheckEx(INVALID_PROCESS_ATTACH_ATTEMPT,
                     (ULONG_PTR)Process,
                     (ULONG_PTR)Thread->ApcState.Process,
                     (ULONG)Thread->ApcStateIndex,
                     (ULONG)KeIsExecutingDpc());

    } else {
        KiAttachProcess(Thread, Process, OldIrql, &Thread->SavedApcState);
    }

    return;
}
Esempio n. 10
0
BOOLEAN
KeConnectInterrupt (
    __inout PKINTERRUPT Interrupt
    )

/*++

Routine Description:

    This function connects an interrupt object to the interrupt vector
    specified by the interrupt object. If the interrupt object is already
    connected, or an attempt is made to connect to an interrupt that cannot
    be connected, then a value of FALSE is returned. Else the specified
    interrupt object is connected to the interrupt vector, the connected
    state is set to TRUE, and TRUE is returned as the function value.

Arguments:

    Interrupt - Supplies a pointer to a control object of type interrupt.

Return Value:

    If the interrupt object is already connected or an attempt is made to
    connect to an interrupt vector that cannot be connected, then a value
    of FALSE is returned. Else a value of TRUE is returned.

--*/

{
    DISPATCH_INFO DispatchInfo;
    BOOLEAN Connected;
    BOOLEAN ConnectError;
    BOOLEAN Enabled;
    KIRQL Irql;
    CCHAR Number;
    KIRQL OldIrql;
    ULONG Vector;

    //
    // If the interrupt object is already connected, the interrupt vector
    // number is invalid, an attempt is being made to connect to a vector
    // that cannot be connected, the interrupt request level is invalid, or
    // the processor number is invalid, then do not connect the interrupt
    // object. Else connect interrupt object to the specified vector and
    // establish the proper interrupt dispatcher.
    //

    Connected = FALSE;
    ConnectError = FALSE;
    Irql = Interrupt->Irql;
    Number = Interrupt->Number;
    Vector = Interrupt->Vector;
    if ( !((Irql > HIGH_LEVEL) ||
           (Number >= KeNumberProcessors) ||
           (Interrupt->SynchronizeIrql < Irql) ||
           (Interrupt->FloatingSave)    // R0 x87 usage not supported on x86
          )
       ) {

        //
        //
        // Set system affinity to the specified processor.
        //

        KeSetSystemAffinityThread((KAFFINITY)(1<<Number));

        //
        // Raise IRQL to dispatcher level and lock dispatcher database.
        //

        KiLockDispatcherDatabase(&OldIrql);

        //
        // Is interrupt object already connected?
        //

        if (!Interrupt->Connected) {

            //
            // Determine interrupt dispatch vector
            //

            KiGetVectorInfo (
                Vector,
                &DispatchInfo
                );

            //
            // If dispatch vector is not connected, then connect it
            //

            if (DispatchInfo.Type == NoConnect) {
                Connected = TRUE;
                Interrupt->Connected = TRUE;

                //
                // Connect interrupt dispatch to interrupt object dispatch code
                //

                InitializeListHead(&Interrupt->InterruptListEntry);
                KiConnectVectorAndInterruptObject (Interrupt, NormalConnect);

                //
                // Enabled system vector
                //

                Enabled = HalEnableSystemInterrupt(Vector, Irql, Interrupt->Mode);
                if (!Enabled) {
                    ConnectError = TRUE;
                }


            } else if (DispatchInfo.Type != UnknownConnect &&
                       Interrupt->ShareVector  &&
                       DispatchInfo.Interrupt->ShareVector  &&
                       DispatchInfo.Interrupt->Mode == Interrupt->Mode) {

                //
                // Vector is already connected as sharable.  New vector is sharable
                // and modes match.  Chain new vector.
                //

                Connected = TRUE;
                Interrupt->Connected = TRUE;

                ASSERT (Irql <= SYNCH_LEVEL);

                //
                // If not already using chained dispatch handler, set it up
                //

                if (DispatchInfo.Type != ChainConnect) {
                    KiConnectVectorAndInterruptObject (DispatchInfo.Interrupt, ChainConnect);
                }

                //
                // Add to tail of chained dispatch
                //

                InsertTailList(
                    &DispatchInfo.Interrupt->InterruptListEntry,
                    &Interrupt->InterruptListEntry
                    );

            }
        }

        //
        // Unlock dispatcher database and lower IRQL to its previous value.
        //

        KiUnlockDispatcherDatabase(OldIrql);

        //
        // Set system affinity back to the original value.
        //

        KeRevertToUserAffinityThread();
    }

    if (Connected  &&  ConnectError) {
#if DBG
        DbgPrint ("HalEnableSystemInterrupt failed\n");
#endif
        KeDisconnectInterrupt (Interrupt);
        Connected = FALSE;
    }

    //
    // Return whether interrupt was connected to the specified vector.
    //

    return Connected;
}
Esempio n. 11
0
LOGICAL
KeForceAttachProcess (
    IN PRKPROCESS Process
    )

/*++

Routine Description:

    This function forces an attach of a thread to a target process' address
    space if the process is not current being swapped into or out of memory.

    N.B. This function is for use by memory management ONLY.

Arguments:

    Process - Supplies a pointer to a dispatcher object of type process.

Return Value:

    None.

--*/

{

    KIRQL OldIrql;
    PRKTHREAD Thread;

    ASSERT_PROCESS(Process);
    ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);

    //
    // Raise IRQL to dispatcher level and lock dispatcher database.
    //

    Thread = KeGetCurrentThread();
    KiLockDispatcherDatabase(&OldIrql);

    //
    // Check whether there is already a process address space attached or
    // the thread is executing a DPC. If either condition is true, then call
    // bug check.
    //

    if ((Thread->ApcStateIndex != 0) ||
        (KeIsExecutingDpc() != FALSE)) {
        KeBugCheckEx(INVALID_PROCESS_ATTACH_ATTEMPT,
                     (ULONG_PTR)Process,
                     (ULONG_PTR)Thread->ApcState.Process,
                     (ULONG)Thread->ApcStateIndex,
                     (ULONG)KeIsExecutingDpc());
    }

    //
    // If the target process is not the current process, then attach the target
    // process if the process is not currently being swapped in or out of memory.
    //

    if (Thread->ApcState.Process == Process) {
        KiUnlockDispatcherDatabase(OldIrql);

    } else {

        //
        // If the target process is currently being swapped into or out of memory,
        // then return a value of FALSE. Otherwise, force the process to be inswapped.
        //

        if ((Process->State == ProcessInSwap) || Process->State == ProcessOutSwap) {
            KiUnlockDispatcherDatabase(OldIrql);
            return FALSE;

        } else {

            //
            // If the target process is in transition, then remove it from its
            // transition list.
            //

            if (Process->State == ProcessInTransition) {
                RemoveEntryList(&Process->SwapListEntry);
            }

            //
            // Force the process state to in memory and attach the target process.
            //

            Process->State = ProcessInMemory;
            KiAttachProcess(Thread, Process, OldIrql, &Thread->SavedApcState);
        }
    }

    return TRUE;
}
Esempio n. 12
0
LONG
KeSetEvent (
    __inout PRKEVENT Event,
    __in KPRIORITY Increment,
    __in BOOLEAN Wait
    )

/*++

Routine Description:

    This function sets the signal state of an event object to signaled
    and attempts to satisfy as many waits as possible. The previous
    signal state of the event object is returned as the function value.

Arguments:

    Event - Supplies a pointer to a dispatcher object of type event.

    Increment - Supplies the priority increment that is to be applied
       if setting the event causes a Wait to be satisfied.

    Wait - Supplies a boolean value that signifies whether the call to
       set event will be immediately followed by a call to one of the
       kernel Wait functions.

Return Value:

    The previous signal state of the event object.

--*/

{

    KIRQL OldIrql;
    LONG OldState;
    PRKTHREAD Thread;

    ASSERT_EVENT(Event);
    ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);

    //
    // If the event is a notification event, the event is already signaled,
    // and wait is false, then there is no need to set the event.
    //

    if ((Event->Header.Type == EventNotificationObject) &&
        (Event->Header.SignalState == 1) &&
        (Wait == FALSE)) {

        return 1;
    }

    //
    // Raise IRQL to dispatcher level and lock dispatcher database.
    //

    KiLockDispatcherDatabase(&OldIrql);

    //
    // Capture the old state and set the new state to signaled.
    //
    // If the old state is not-signaled and the wait list is not empty,
    // then satisfy as many waits as possible.
    //

    OldState = ReadForWriteAccess(&Event->Header.SignalState);
    Event->Header.SignalState = 1;
    if ((OldState == 0) &&
        (IsListEmpty(&Event->Header.WaitListHead) == FALSE)) {

        if (Event->Header.Type == EventNotificationObject) {
            KiWaitTestWithoutSideEffects(Event, Increment);

        } else {
            KiWaitTestSynchronizationObject(Event, Increment);
        }
    }

    //
    // If the value of the Wait argument is TRUE, then return to the
    // caller with IRQL raised and the dispatcher database locked. Else
    // release the dispatcher database lock and lower IRQL to its
    // previous value.
    //

    if (Wait != FALSE) {
       Thread = KeGetCurrentThread();
       Thread->WaitNext = Wait;
       Thread->WaitIrql = OldIrql;

    } else {
       KiUnlockDispatcherDatabase(OldIrql);
    }

    //
    // Return previous signal state of event object.
    //

    return OldState;
}
Esempio n. 13
0
VOID 
KeDetachSessionSpace(
    VOID
    )
/*++

 Routine Description:
    
    This routine removes the session space and synchronize the all threads on 
    the other processors.

 Arguments:
 
    DeleteSessionMapInfo - if TRUE, the session map info will be deleted.
        if FALSE, the session map info will not be deleted.

 Return Value:
  
    None.

 Environment:
 
    Kernel mode.

--*/
{
    KIRQL OldIrql;
    PKTHREAD Thread;
    PKPROCESS Process;
#if !defined(NT_UP)
    KAFFINITY TargetProcessors;
#endif

    //
    // Raise IRQL to dispatcher level and lock the dispatcher database.
    //

    KiLockDispatcherDatabase(&OldIrql);

    Thread = KeGetCurrentThread();
    Process = Thread->ApcState.Process;

    //
    // Lock the region Id resource.
    //
    
    KiAcquireSpinLock(&KiMasterRidLock);

    Process->SessionMapInfo = &Process->SessionRegion;
    
    KiSetRegionRegister((PVOID)MM_SESSION_SPACE_DEFAULT, 
                        KiMakeValidRegionRegister(Process->SessionMapInfo->RegionId, PAGE_SHIFT));

    //
    // Unlock the region Id resource.
    //

    KiReleaseSpinLock(&KiMasterRidLock);

#if !defined(NT_UP)

    //
    // broadcast Region Id sync
    //

    TargetProcessors = KeActiveProcessors;
    TargetProcessors &= PCR->NotMember;

    if (TargetProcessors != 0) {
        KiIpiSendPacket(TargetProcessors,
                        KiSyncSessionTarget,
                        Process,
                        NULL,
                        NULL);
    }

#endif

    //
    // Unlock the dispatcher database
    //

    KiUnlockDispatcherDatabase(OldIrql);
}    
Esempio n. 14
0
KPRIORITY
KeSetPriorityProcess (
    IN PKPROCESS Process,
    IN KPRIORITY NewBase
    )

/*++

Routine Description:

    This function set the base priority of a process to a new value
    and adjusts the priority and base priority of all child threads
    as appropriate.

Arguments:

    Process - Supplies a pointer to a dispatcher object of type process.

    NewBase - Supplies the new base priority of the process.

Return Value:

    The previous base priority of the process.

--*/

{

    KPRIORITY Adjustment;
    PLIST_ENTRY NextEntry;
    KPRIORITY NewPriority;
    KIRQL OldIrql;
    KPRIORITY OldBase;
    PKTHREAD Thread;

    ASSERT_PROCESS(Process);
    ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);

    //
    // Raise IRQL to dispatcher level and lock dispatcher database.
    //

    KiLockDispatcherDatabase(&OldIrql);

    //
    // Save the current process base priority, set the new process base
    // priority, compute the adjustment value, and adjust the priority
    // and base priority of all child threads as appropriate.
    //

    OldBase = Process->BasePriority;
    Process->BasePriority = (SCHAR)NewBase;
    Adjustment = NewBase - OldBase;
    NextEntry = Process->ThreadListHead.Flink;
    if (NewBase >= LOW_REALTIME_PRIORITY) {
        while (NextEntry != &Process->ThreadListHead) {
            Thread = CONTAINING_RECORD(NextEntry, KTHREAD, ThreadListEntry);

            //
            // Compute the new base priority of the thread.
            //

            NewPriority = Thread->BasePriority + Adjustment;

            //
            // If the new base priority is outside the realtime class,
            // then limit the change to the realtime class.
            //

            if (NewPriority < LOW_REALTIME_PRIORITY) {
                NewPriority = LOW_REALTIME_PRIORITY;

            } else if (NewPriority > HIGH_PRIORITY) {
                NewPriority = HIGH_PRIORITY;
            }

            //
            // Set the base priority and the current priority of the
            // thread to the appropriate value.
            //
            // N.B. If priority saturation occured the last time the thread
            //      base priority was set and the new process base priority
            //      is not crossing from variable to realtime, then it is not
            //      necessary to change the thread priority.
            //

            if ((Thread->Saturation == 0) || (OldBase < LOW_REALTIME_PRIORITY)) {
                if (Thread->Saturation > 0) {
                    NewPriority = HIGH_PRIORITY;

                } else if (Thread->Saturation < 0) {
                    NewPriority = LOW_REALTIME_PRIORITY;
                }

                Thread->BasePriority = (SCHAR)NewPriority;
                Thread->Quantum = Process->ThreadQuantum;
                Thread->DecrementCount = 0;
                Thread->PriorityDecrement = 0;
                KiSetPriorityThread(Thread, NewPriority);
            }

            NextEntry = NextEntry->Flink;
        }

    } else {
        while (NextEntry != &Process->ThreadListHead) {
            Thread = CONTAINING_RECORD(NextEntry, KTHREAD, ThreadListEntry);

            //
            // Compute the new base priority of the thread.
            //

            NewPriority = Thread->BasePriority + Adjustment;

            //
            // If the new base priority is outside the variable class,
            // then limit the change to the variable class.
            //

            if (NewPriority >= LOW_REALTIME_PRIORITY) {
                NewPriority = LOW_REALTIME_PRIORITY - 1;

            } else if (NewPriority <= LOW_PRIORITY) {
                NewPriority = 1;
            }

            //
            // Set the base priority and the current priority of the
            // thread to the computed value and reset the thread quantum.
            //
            // N.B. If priority saturation occured the last time the thread
            //      base priority was set and the new process base priority
            //      is not crossing from realtime to variable, then it is not
            //      necessary to change the thread priority.
            //

            if ((Thread->Saturation == 0) || (OldBase >= LOW_REALTIME_PRIORITY)) {
                if (Thread->Saturation > 0) {
                    NewPriority = LOW_REALTIME_PRIORITY - 1;

                } else if (Thread->Saturation < 0) {
                    NewPriority = 1;
                }

                Thread->BasePriority = (SCHAR)NewPriority;
                Thread->Quantum = Process->ThreadQuantum;
                Thread->DecrementCount = 0;
                Thread->PriorityDecrement = 0;
                KiSetPriorityThread(Thread, NewPriority);
            }

            NextEntry = NextEntry->Flink;
        }
    }

    //
    // Unlock dispatcher database and lower IRQL to its previous
    // value.
    //

    KiUnlockDispatcherDatabase(OldIrql);

    //
    // Return previous process base priority
    //

    return OldBase;
}
Esempio n. 15
0
LONG
KeSetProcess (
    IN PRKPROCESS Process,
    IN KPRIORITY Increment,
    IN BOOLEAN Wait
    )

/*++

Routine Description:

    This function sets the signal state of a proces object to Signaled
    and attempts to satisfy as many Waits as possible. The previous
    signal state of the process object is returned as the function value.

Arguments:

    Process - Supplies a pointer to a dispatcher object of type process.

    Increment - Supplies the priority increment that is to be applied
       if setting the process causes a Wait to be satisfied.

    Wait - Supplies a boolean value that signifies whether the call to
       KeSetProcess will be immediately followed by a call to one of the
       kernel Wait functions.

Return Value:

    The previous signal state of the process object.

--*/

{

    KIRQL OldIrql;
    LONG OldState;
    PRKTHREAD Thread;

    ASSERT_PROCESS(Process);
    ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);

    //
    // Raise IRQL to dispatcher level and lock dispatcher database.
    //

    KiLockDispatcherDatabase(&OldIrql);

    //
    // If the previous state of the process object is Not-Signaled and
    // the wait queue is not empty, then satisfy as many Waits as
    // possible.
    //

    OldState = Process->Header.SignalState;
    Process->Header.SignalState = 1;
    if ((OldState == 0) && (!IsListEmpty(&Process->Header.WaitListHead))) {
        KiWaitTest(Process, Increment);
    }

    //
    // If the value of the Wait argument is TRUE, then return to the
    // caller with IRQL raised and the dispatcher database locked. Else
    // release the dispatcher database lock and lower IRQL to its
    // previous value.
    //

    if (Wait) {
        Thread = KeGetCurrentThread();
        Thread->WaitNext = Wait;
        Thread->WaitIrql = OldIrql;

    } else {
        KiUnlockDispatcherDatabase(OldIrql);
    }

    //
    // Return previous signal state of process object.
    //

    return OldState;
}
Esempio n. 16
0
VOID
KeUnstackDetachProcess (
    IN PRKAPC_STATE ApcState
    )

/*++

Routine Description:

    This function detaches a thread from another process' address space
    and restores previous attach state.

Arguments:

    ApcState - Supplies a pointer to an APC state structure that was returned
        from a previous call to stack attach process.

Return Value:

    None.

--*/

{

    KIRQL OldIrql;
    PKPROCESS Process;
    PKTHREAD Thread;

    ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);

    //
    // Raise IRQL to dispatcher level and lock dispatcher database.
    //

    Thread = KeGetCurrentThread();
    KiLockDispatcherDatabase(&OldIrql);

    //
    // If the APC state has a distinguished process pointer value, then no
    // attach was performed on the paired call to stack attach process.
    //

    if (ApcState->Process != (PRKPROCESS)1) {

        //
        // If the current thread is not attached to another process, a kernel
        // APC is in progress, or either the kernel or user mode APC queues
        // are not empty, then call bug check.
        //

        if ((Thread->ApcStateIndex == 0) ||
             (Thread->ApcState.KernelApcInProgress) ||
             (IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode]) == FALSE) ||
             (IsListEmpty(&Thread->ApcState.ApcListHead[UserMode]) == FALSE)) {
            KeBugCheck(INVALID_PROCESS_DETACH_ATTEMPT);
        }

        //
        // Unbias current process stack count and check if the process should
        // be swapped out of memory.
        //

        Process = Thread->ApcState.Process;
        Process->StackCount -= 1;
        if ((Process->StackCount == 0) &&
            (IsListEmpty(&Process->ThreadListHead) == FALSE)) {
            Process->State = ProcessInTransition;
            InsertTailList(&KiProcessOutSwapListHead, &Process->SwapListEntry);
            KiSwapEvent.Header.SignalState = 1;
            if (IsListEmpty(&KiSwapEvent.Header.WaitListHead) == FALSE) {
                KiWaitTest(&KiSwapEvent, BALANCE_INCREMENT);
            }
        }

        //
        // Restore APC state and check whether the kernel APC queue contains
        // an entry. If the kernel APC queue contains an entry then set kernel
        // APC pending and request a software interrupt at APC_LEVEL.
        //

        if (ApcState->Process != NULL) {
            KiMoveApcState(ApcState, &Thread->ApcState);

        } else {
            KiMoveApcState(&Thread->SavedApcState, &Thread->ApcState);
            Thread->SavedApcState.Process = (PKPROCESS)NULL;
            Thread->ApcStatePointer[0] = &Thread->ApcState;
            Thread->ApcStatePointer[1] = &Thread->SavedApcState;
            Thread->ApcStateIndex = 0;
        }

        if (IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode]) == FALSE) {
            Thread->ApcState.KernelApcPending = TRUE;
            KiRequestSoftwareInterrupt(APC_LEVEL);
        }

        //
        // Swap the address space back to the parent process.
        //

        KiSwapProcess(Thread->ApcState.Process, Process);
    }

    //
    // Lower IRQL to its previous value and return.
    //

    KiUnlockDispatcherDatabase(OldIrql);
    return;
}
Esempio n. 17
0
VOID
KeDetachProcess (
    VOID
    )

/*++

Routine Description:

    This function detaches a thread from another process' address space.

Arguments:

    None.

Return Value:

    None.

--*/

{

    KIRQL OldIrql;
    PKPROCESS Process;
    PKTHREAD Thread;

    ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);

    //
    // Raise IRQL to dispatcher level and lock dispatcher database.
    //

    Thread = KeGetCurrentThread();
    KiLockDispatcherDatabase(&OldIrql);

    //
    // If the current thread is attached to another process, then detach
    // it.
    //

    if (Thread->ApcStateIndex != 0) {

        //
        // Check if a kernel APC is in progress, the kernel APC queue is
        // not empty, or the user APC queue is not empty. If any of these
        // conditions are true, then call bug check.
        //

#if DBG

        if ((Thread->ApcState.KernelApcInProgress) ||
            (IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode]) == FALSE) ||
            (IsListEmpty(&Thread->ApcState.ApcListHead[UserMode]) == FALSE)) {
            KeBugCheck(INVALID_PROCESS_DETACH_ATTEMPT);
        }

#endif

        //
        // Unbias current process stack count and check if the process should
        // be swapped out of memory.
        //

        Process = Thread->ApcState.Process;
        Process->StackCount -= 1;
        if ((Process->StackCount == 0) &&
            (IsListEmpty(&Process->ThreadListHead) == FALSE)) {
            Process->State = ProcessInTransition;
            InsertTailList(&KiProcessOutSwapListHead, &Process->SwapListEntry);
            KiSwapEvent.Header.SignalState = 1;
            if (IsListEmpty(&KiSwapEvent.Header.WaitListHead) == FALSE) {
                KiWaitTest(&KiSwapEvent, BALANCE_INCREMENT);
            }
        }

        //
        // Restore APC state and check whether the kernel APC queue contains
        // an entry. If the kernel APC queue contains an entry then set kernel
        // APC pending and request a software interrupt at APC_LEVEL.
        //

        KiMoveApcState(&Thread->SavedApcState, &Thread->ApcState);
        Thread->SavedApcState.Process = (PKPROCESS)NULL;
        Thread->ApcStatePointer[0] = &Thread->ApcState;
        Thread->ApcStatePointer[1] = &Thread->SavedApcState;
        Thread->ApcStateIndex = 0;
        if (IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode]) == FALSE) {
            Thread->ApcState.KernelApcPending = TRUE;
            KiRequestSoftwareInterrupt(APC_LEVEL);
        }

        //
        // Swap the address space back to the parent process.
        //

        KiSwapProcess(Thread->ApcState.Process, Process);
    }

    //
    // Lower IRQL to its previous value and return.
    //

    KiUnlockDispatcherDatabase(OldIrql);
    return;
}
Esempio n. 18
0
VOID
KeStackAttachProcess (
    IN PRKPROCESS Process,
    OUT PRKAPC_STATE ApcState
    )

/*++

Routine Description:

    This function attaches a thread to a target process' address space
    and returns information about a previous attached process.

Arguments:

    Process - Supplies a pointer to a dispatcher object of type process.

Return Value:

    None.

--*/

{

    KIRQL OldIrql;
    PRKTHREAD Thread;

    ASSERT_PROCESS(Process);
    ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);

    //
    // Raise IRQL to dispatcher level and lock dispatcher database.
    //

    Thread = KeGetCurrentThread();
    KiLockDispatcherDatabase(&OldIrql);

    //
    // If the current thread is executing a DPC, then bug check.
    //

    if (KeIsExecutingDpc() != FALSE) {
        KeBugCheckEx(INVALID_PROCESS_ATTACH_ATTEMPT,
                     (ULONG_PTR)Process,
                     (ULONG_PTR)Thread->ApcState.Process,
                     (ULONG)Thread->ApcStateIndex,
                     (ULONG)KeIsExecutingDpc());
    }

    //
    // If the target process is not the current process, then attach the target
    // process. Otherwise, return a distinguished process value to indicate that
    // an attach was not performed.
    //

    if (Thread->ApcState.Process == Process) {
        KiUnlockDispatcherDatabase(OldIrql);
        ApcState->Process = (PRKPROCESS)1;

    } else {

        //
        // If the current thread is attached to a process, then save the current
        // APC state in the callers APC state structure. Otherwise, save the
        // current APC state in the saved APC state structure, and return a NULL
        // process pointer.
        //

        if (Thread->ApcStateIndex != 0) {
            KiAttachProcess(Thread, Process, OldIrql, ApcState);

        } else {
            KiAttachProcess(Thread, Process, OldIrql, &Thread->SavedApcState);
            ApcState->Process = NULL;
        }
    }

    return;
}
Esempio n. 19
0
VOID
KeSetSystemTime (
    IN PLARGE_INTEGER NewTime,
    OUT PLARGE_INTEGER OldTime,
    IN BOOLEAN AdjustInterruptTime,
    IN PLARGE_INTEGER HalTimeToSet OPTIONAL
    )

/*++

Routine Description:

    This function sets the system time to the specified value and updates
    timer queue entries to reflect the difference between the old system
    time and the new system time.

Arguments:

    NewTime - Supplies a pointer to a variable that specifies the new system
        time.

    OldTime - Supplies a pointer to a variable that will receive the previous
        system time.

    AdjustInterruptTime - If TRUE the amount of time being adjusted is
        also applied to InterruptTime and TickCount.

    HalTimeToSet - Supplies an optional time that if specified is to be used
        to set the time in the realtime clock.

Return Value:

    None.

--*/

{

    LIST_ENTRY AbsoluteListHead;
    LIST_ENTRY ExpiredListHead;
    ULONG Hand;
    ULONG Index;
    PLIST_ENTRY ListHead;
    PKSPIN_LOCK_QUEUE LockQueue;
    PLIST_ENTRY NextEntry;
    KIRQL OldIrql1;
    KIRQL OldIrql2;
    LARGE_INTEGER TimeDelta;
    TIME_FIELDS TimeFields;
    PKTIMER Timer;

    ASSERT((NewTime->HighPart & 0xf0000000) == 0);

    ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);

    //
    // If a realtime clock value is specified, then convert the time value
    // to time fields.
    //

    if (ARGUMENT_PRESENT(HalTimeToSet)) {
        RtlTimeToTimeFields(HalTimeToSet, &TimeFields);
    }

    //
    // Set affinity to the processor that keeps the system time, raise IRQL
    // to dispatcher level and lock the dispatcher database, then raise IRQL
    // to HIGH_LEVEL to synchronize with the clock interrupt routine.
    //

    KeSetSystemAffinityThread((KAFFINITY)1);
    KiLockDispatcherDatabase(&OldIrql1);
    KeRaiseIrql(HIGH_LEVEL, &OldIrql2);

    //
    // Save the previous system time, set the new system time, and set
    // the realtime clock, if a time value is specified.
    //

    KiQuerySystemTime(OldTime);

#if defined(_AMD64_)

    SharedUserData->SystemTime.High2Time = NewTime->HighPart;
    *((volatile ULONG64 *)&SharedUserData->SystemTime) = NewTime->QuadPart;

#else

    SharedUserData->SystemTime.High2Time = NewTime->HighPart;
    SharedUserData->SystemTime.LowPart   = NewTime->LowPart;
    SharedUserData->SystemTime.High1Time = NewTime->HighPart;

#endif

    if (ARGUMENT_PRESENT(HalTimeToSet)) {
        ExCmosClockIsSane = HalSetRealTimeClock(&TimeFields);
    }

    //
    // Compute the difference between the previous system time and the new
    // system time.
    //

    TimeDelta.QuadPart = NewTime->QuadPart - OldTime->QuadPart;

    //
    // Update the boot time to reflect the delta. This keeps time based
    // on boot time constant
    //

    KeBootTime.QuadPart = KeBootTime.QuadPart + TimeDelta.QuadPart;

    //
    // Track the overall bias applied to the boot time.
    //

    KeBootTimeBias = KeBootTimeBias + TimeDelta.QuadPart;

    //
    // Lower IRQL to dispatch level and if needed adjust the physical
    // system interrupt time.
    //

    KeLowerIrql(OldIrql2);
    if (AdjustInterruptTime != FALSE) {
        AdjustInterruptTime = KeAdjustInterruptTime(TimeDelta.QuadPart);
    }

    //
    // If the physical interrupt time of the system was not adjusted, then
    // recompute any absolute timers in the system for the new system time.
    //

    if (AdjustInterruptTime == FALSE) {

        //
        // Acquire the timer table lock, remove all absolute timers from the
        // timer queue so their due time can be recomputed, and release the
        // timer table lock.
        //

        InitializeListHead(&AbsoluteListHead);
        for (Index = 0; Index < TIMER_TABLE_SIZE; Index += 1) {
            ListHead = &KiTimerTableListHead[Index].Entry;
            LockQueue = KiAcquireTimerTableLock(Index);
            NextEntry = ListHead->Flink;
            while (NextEntry != ListHead) {
                Timer = CONTAINING_RECORD(NextEntry, KTIMER, TimerListEntry);
                NextEntry = NextEntry->Flink;
                if (Timer->Header.Absolute != FALSE) {
                    KiRemoveEntryTimer(Timer);
                    InsertTailList(&AbsoluteListHead, &Timer->TimerListEntry);
                }
            }

            KiReleaseTimerTableLock(LockQueue);
        }

        //
        // Recompute the due time and reinsert all absolute timers in the timer
        // tree. If a timer has already expired, then insert the timer in the
        // expired timer list.
        //

        InitializeListHead(&ExpiredListHead);
        while (AbsoluteListHead.Flink != &AbsoluteListHead) {
            Timer = CONTAINING_RECORD(AbsoluteListHead.Flink, KTIMER, TimerListEntry);
            RemoveEntryList(&Timer->TimerListEntry);
            Timer->DueTime.QuadPart -= TimeDelta.QuadPart;
            Hand = KiComputeTimerTableIndex(Timer->DueTime.QuadPart);
            Timer->Header.Hand = (UCHAR)Hand;
            LockQueue = KiAcquireTimerTableLock(Hand);
            if (KiInsertTimerTable(Timer, Hand) == TRUE) {
                KiRemoveEntryTimer(Timer);
                InsertTailList(&ExpiredListHead, &Timer->TimerListEntry);
            }

            KiReleaseTimerTableLock(LockQueue);
        }

        //
        // If any of the attempts to reinsert a timer failed, then timers have
        // already expired and must be processed.
        //
        // N.B. The following function returns with the dispatcher database
        //      unlocked.
        //

        KiTimerListExpire(&ExpiredListHead, OldIrql1);

    } else {
        KiUnlockDispatcherDatabase(OldIrql1);
    }

    //
    // Set affinity back to its original value.
    //

    KeRevertToUserAffinityThread();
    return;
}
Esempio n. 20
0
VOID
KiTimerExpiration (
    IN PKDPC TimerDpc,
    IN PVOID DeferredContext,
    IN PVOID SystemArgument1,
    IN PVOID SystemArgument2
    )

/*++

Routine Description:

    This function is called when the clock interupt routine discovers that
    a timer has expired.

Arguments:

    TimerDpc - Supplies a pointer to a control object of type DPC.

    DeferredContext - Not used.

    SystemArgument1 - Supplies the starting timer table index value to
        use for the timer table scan.

    SystemArgument2 - Not used.

Return Value:

    None.

--*/

{
    ULARGE_INTEGER CurrentTime;
    LIST_ENTRY ExpiredListHead;
    LONG HandLimit;
    LONG Index;
    PLIST_ENTRY ListHead;
    PLIST_ENTRY NextEntry;
    KIRQL OldIrql;
    PKTIMER Timer;

    //
    // Acquire the dispatcher database lock and read the current interrupt
    // time to determine which timers have expired.
    //

    KiLockDispatcherDatabase(&OldIrql);
    KiQueryInterruptTime((PLARGE_INTEGER)&CurrentTime);

    //
    // If the timer table has not wrapped, then start with the specified
    // timer table index value, and scan for timer entries that have expired.
    // Otherwise, start with the first entry in the timer table and scan the
    // entire table for timer entries that have expired.
    //
    // N.B. This later condition exists when DPC processing is blocked for a
    //      period longer than one round trip throught the timer table.
    //

    HandLimit = (LONG)KiQueryLowTickCount();
    if (((ULONG)(HandLimit - PtrToLong(SystemArgument1))) >= TIMER_TABLE_SIZE) {
        Index = - 1;
        HandLimit = TIMER_TABLE_SIZE - 1;

    } else {
        Index = (PtrToLong(SystemArgument1) - 1) & (TIMER_TABLE_SIZE - 1);
        HandLimit &= (TIMER_TABLE_SIZE - 1);
    }

    InitializeListHead(&ExpiredListHead);
    do {
        Index = (Index + 1) & (TIMER_TABLE_SIZE - 1);
        ListHead = &KiTimerTableListHead[Index];
        NextEntry = ListHead->Flink;
        while (NextEntry != ListHead) {
            Timer = CONTAINING_RECORD(NextEntry, KTIMER, TimerListEntry);
            if (Timer->DueTime.QuadPart <= CurrentTime.QuadPart) {

                //
                // The next timer in the current timer list has expired.
                // Remove the entry from the timer list and insert the
                // timer in the expired list.
                //

                RemoveEntryList(&Timer->TimerListEntry);
                InsertTailList(&ExpiredListHead, &Timer->TimerListEntry);
                NextEntry = ListHead->Flink;

            } else {
                break;
            }
        }

    } while(Index != HandLimit);

#if DBG

    if ((PtrToUlong(SystemArgument2) == 0) && (KeNumberProcessors == 1)) {
        KiCheckTimerTable(CurrentTime);
    }

#endif

    //
    // Process the expired timer list.
    //
    // N.B. The following function returns with the dispatcher database
    //      unlocked.
    //

    KiTimerListExpire(&ExpiredListHead, OldIrql);
    return;
}
Esempio n. 21
0
LONG
KePulseEvent (
    __inout PRKEVENT Event,
    __in KPRIORITY Increment,
    __in BOOLEAN Wait
    )

/*++

Routine Description:

    This function atomically sets the signal state of an event object to
    signaled, attempts to satisfy as many waits as possible, and then resets
    the signal state of the event object to Not-Signaled. The previous signal
    state of the event object is returned as the function value.

Arguments:

    Event - Supplies a pointer to a dispatcher object of type event.

    Increment - Supplies the priority increment that is to be applied
       if setting the event causes a Wait to be satisfied.

    Wait - Supplies a boolean value that signifies whether the call to
       KePulseEvent will be immediately followed by a call to one of the
       kernel Wait functions.

Return Value:

    The previous signal state of the event object.

--*/

{

    KIRQL OldIrql;
    LONG OldState;
    PRKTHREAD Thread;

    ASSERT_EVENT(Event);
    ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);

    //
    // Raise IRQL to dispatcher level and lock dispatcher database.
    //

    KiLockDispatcherDatabase(&OldIrql);

    //
    // If the current state of the event object is Not-Signaled and
    // the wait queue is not empty, then set the state of the event
    // to Signaled, satisfy as many Waits as possible, and then reset
    // the state of the event to Not-Signaled.
    //

    OldState = ReadForWriteAccess(&Event->Header.SignalState);
    if ((OldState == 0) &&
        (IsListEmpty(&Event->Header.WaitListHead) == FALSE)) {

        Event->Header.SignalState = 1;
        KiWaitTest(Event, Increment);
    }

    Event->Header.SignalState = 0;

    //
    // If the value of the Wait argument is TRUE, then return to the
    // caller with IRQL raised and the dispatcher database locked. Else
    // release the dispatcher database lock and lower IRQL to the
    // previous value.
    //

    if (Wait != FALSE) {
        Thread = KeGetCurrentThread();
        Thread->WaitIrql = OldIrql;
        Thread->WaitNext = Wait;

    } else {
       KiUnlockDispatcherDatabase(OldIrql);
    }

    //
    // Return previous signal state of event object.
    //

    return OldState;
}
Esempio n. 22
0
VOID
FASTCALL
KiTimerListExpire (
    IN PLIST_ENTRY ExpiredListHead,
    IN KIRQL OldIrql
    )

/*++

Routine Description:

    This function is called to process a list of timers that have expired.

    N.B. This function is called with the dispatcher database locked and
        returns with the dispatcher database unlocked.

Arguments:

    ExpiredListHead - Supplies a pointer to a list of timers that have
        expired.

    OldIrql - Supplies the previous IRQL.

Return Value:

    None.

--*/

{

    LONG Count;
    PKDPC Dpc;
    DPC_ENTRY DpcList[MAXIMUM_DPC_LIST_SIZE];
    LONG Index;
    LARGE_INTEGER Interval;
    KIRQL OldIrql1;
    LARGE_INTEGER SystemTime;
    PKTIMER Timer;

    //
    // Capture the timer expiration time.
    //

    KiQuerySystemTime(&SystemTime);

    //
    // Remove the next timer from the expired timer list, set the state of
    // the timer to signaled, reinsert the timer in the timer tree if it is
    // periodic, and optionally call the DPC routine if one is specified.
    //

RestartScan:
    Count = 0;
    while (ExpiredListHead->Flink != ExpiredListHead) {
        Timer = CONTAINING_RECORD(ExpiredListHead->Flink, KTIMER, TimerListEntry);
        KiRemoveTreeTimer(Timer);
        Timer->Header.SignalState = 1;
        if (IsListEmpty(&Timer->Header.WaitListHead) == FALSE) {
            KiWaitTest(Timer, TIMER_EXPIRE_INCREMENT);
        }

        //
        // If the timer is periodic, then compute the next interval time
        // and reinsert the timer in the timer tree.
        //
        // N.B. Even though the timer insertion is relative, it can still
        //      fail if the period of the timer elapses in between computing
        //      the time and inserting the timer in the table. If this happens,
        //      try again.
        //
        if (Timer->Period != 0) {
            Interval.QuadPart = Int32x32To64(Timer->Period, - 10 * 1000);
            while (!KiInsertTreeTimer(Timer, Interval)) {
                ;
            }
        }

        if (Timer->Dpc != NULL) {
            Dpc = Timer->Dpc;

            //
            // If the DPC is explicitly targeted to another processor, then
            // queue the DPC to the target processor. Otherwise, capture the
            // DPC parameters for execution on the current processor.
            //

#if defined(NT_UP)

            DpcList[Count].Dpc = Dpc;
            DpcList[Count].Routine = Dpc->DeferredRoutine;
            DpcList[Count].Context = Dpc->DeferredContext;
            Count += 1;
            if (Count == MAXIMUM_DPC_LIST_SIZE) {
                break;
            }

#else

            if ((Dpc->Number >= MAXIMUM_PROCESSORS) &&
                (((ULONG)Dpc->Number - MAXIMUM_PROCESSORS) != (ULONG)KeGetCurrentProcessorNumber())) {
                KeInsertQueueDpc(Dpc,
                                 ULongToPtr(SystemTime.LowPart),
                                 ULongToPtr(SystemTime.HighPart));

            } else {
                DpcList[Count].Dpc = Dpc;
                DpcList[Count].Routine = Dpc->DeferredRoutine;
                DpcList[Count].Context = Dpc->DeferredContext;
                Count += 1;
                if (Count == MAXIMUM_DPC_LIST_SIZE) {
                    break;
                }
            }

#endif

        }
    }

    //
    // Unlock the dispacher database and process DPC list entries.
    //

    if (Count != 0) {
        KiUnlockDispatcherDatabase(DISPATCH_LEVEL);
        Index = 0;
        do {

#if DBG && (defined(i386) || defined(ALPHA))

            //
            // Reset the dpc tick count. If the tick count handler,
            // which increments this value, detects that it has crossed
            // a certain threshold, a breakpoint will be generated.
            //

            KeGetCurrentPrcb()->DebugDpcTime = 0;
#endif

            (DpcList[Index].Routine)(DpcList[Index].Dpc,
                                     DpcList[Index].Context,
                                     ULongToPtr(SystemTime.LowPart),
                                     ULongToPtr(SystemTime.HighPart));


            Index += 1;
        } while (Index < Count);

        //
        // If processing of the expired timer list was terminated because
        // the DPC List was full, then process any remaining entries.
        //

        if (Count == MAXIMUM_DPC_LIST_SIZE) {
            KiLockDispatcherDatabase(&OldIrql1);
            goto RestartScan;
        }

        KeLowerIrql(OldIrql);

    } else {
        KiUnlockDispatcherDatabase(OldIrql);
    }

    return;
}
Esempio n. 23
0
VOID
KeSetEventBoostPriority (
    __inout PRKEVENT Event,
    __in_opt PRKTHREAD *Thread
    )

/*++

Routine Description:

    This function conditionally sets the signal state of an event object
    to signaled, and attempts to unwait the first waiter, and optionally
    returns the thread address of the unwaited thread.

    N.B. This function can only be called with synchronization events.

Arguments:

    Event - Supplies a pointer to a dispatcher object of type event.

    Thread - Supplies an optional pointer to a variable that receives
        the address of the thread that is awakened.

Return Value:

    None.

--*/

{

    PKTHREAD CurrentThread;
    KIRQL OldIrql;
    PKWAIT_BLOCK WaitBlock;
    PRKTHREAD WaitThread;

    ASSERT(Event->Header.Type == SynchronizationEvent);
    ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);

    //
    // Raise IRQL to dispatcher level and lock dispatcher database.
    //

    CurrentThread = KeGetCurrentThread();
    KiLockDispatcherDatabase(&OldIrql);

    //
    // If the the wait list is not empty, then satisfy the wait of the
    // first thread in the wait list. Otherwise, set the signal state
    // of the event object.
    //

    if (IsListEmpty(&Event->Header.WaitListHead) != FALSE) {
        Event->Header.SignalState = 1;

    } else {

        //
        // Get the address of the first wait block in the event list.
        // If the wait is a wait any, then set the state of the event
        // to signaled and attempt to satisfy as many waits as possible.
        // Otherwise, unwait the first thread and apply an appropriate
        // priority boost to help prevent lock convoys from forming.
        //
        // N.B. Internal calls to this function for resource and fast
        //      mutex boosts NEVER call with a possibility of having
        //      a wait type of WaitAll. Calls from the NT service to
        //      set event and boost priority are restricted as to the
        //      event type, but not the wait type.
        //

        WaitBlock = CONTAINING_RECORD(Event->Header.WaitListHead.Flink,
                                      KWAIT_BLOCK,
                                      WaitListEntry);

        if (WaitBlock->WaitType == WaitAll) {
            Event->Header.SignalState = 1;
            KiWaitTestSynchronizationObject(Event, EVENT_INCREMENT);

        } else {

            //
            // Get the address of the waiting thread and return the address
            // if requested.
            //

            WaitThread = WaitBlock->Thread;
            if (ARGUMENT_PRESENT(Thread)) {
                *Thread = WaitThread;
            }

            //
            // Compute the new thread priority.
            //

            CurrentThread->Priority = KiComputeNewPriority(CurrentThread, 0);

            //
            // Unlink the thread from the appropriate wait queues and set
            // the wait completion status.
            //

            KiUnlinkThread(WaitThread, STATUS_SUCCESS);

            //
            // Set unwait priority adjustment parameters.
            //

            WaitThread->AdjustIncrement = CurrentThread->Priority;
            WaitThread->AdjustReason = (UCHAR)AdjustBoost;

            //
            // Ready the thread for execution.
            //

            KiReadyThread(WaitThread);
        }
    }

    //
    // Unlock dispatcher database lock and lower IRQL to its previous
    // value.
    //

    KiUnlockDispatcherDatabase(OldIrql);
    return;
}
Esempio n. 24
0
PRKTHREAD
KiQuantumEnd (
    VOID
    )

/*++

Routine Description:

    This function is called when a quantum end event occurs on the current
    processor. Its function is to determine whether the thread priority should
    be decremented and whether a redispatch of the processor should occur.

Arguments:

    None.

Return Value:

    The next thread to be schedule on the current processor is returned as
    the function value. If this value is not NULL, then the return is with
    the dispatcher database locked. Otherwise, the dispatcher database is
    unlocked.

--*/

{

    KPRIORITY NewPriority;
    KIRQL OldIrql;
    PKPRCB Prcb;
    KPRIORITY Priority;
    PKPROCESS Process;
    PRKTHREAD Thread;
    PRKTHREAD NextThread;

    //
    // Acquire the dispatcher database lock.
    //

    Prcb = KeGetCurrentPrcb();
    Thread = KeGetCurrentThread();
    KiLockDispatcherDatabase(&OldIrql);

    //
    // If the quantum has expired for the current thread, then update its
    // quantum and priority.
    //

    if (Thread->Quantum <= 0) {

        //
        // If quantum runout is disabled for the thread's process and
        // the thread is running at a realtime priority, then set the
        // thread quantum to the highest value and do not round robin
        // at the thread's priority level. Otherwise, reset the thread
        // quantum and decay the thread's priority as appropriate.
        //

        Process = Thread->ApcState.Process;
        if ((Process->DisableQuantum != FALSE) &&
            (Thread->Priority >= LOW_REALTIME_PRIORITY)) {
            Thread->Quantum = MAXCHAR;

        } else {
            Thread->Quantum = Process->ThreadQuantum;

            //
            // Decrement the thread's current priority if the thread is not
            // running in a realtime priority class and check to determine
            // if the processor should be redispatched.
            //

            Priority = Thread->Priority;
            if (Priority < LOW_REALTIME_PRIORITY) {
                NewPriority = Priority - Thread->PriorityDecrement - 1;
                if (NewPriority < Thread->BasePriority) {
                    NewPriority = Thread->BasePriority;
                }

                Thread->PriorityDecrement = 0;

            } else {
                NewPriority = Priority;
            }

            //
            // If the new thread priority is different that the current thread
            // priority, then the thread does not run at a realtime level and
            // its priority should be set. Otherwise, attempt to round robin
            // at the current level.
            //

            if (Priority != NewPriority) {
                KiSetPriorityThread(Thread, NewPriority);

            } else {
                if (Prcb->NextThread == NULL) {
                    NextThread = KiFindReadyThread(Thread->NextProcessor, Priority);

                    if (NextThread != NULL) {
                        NextThread->State = Standby;
                        Prcb->NextThread = NextThread;
                    }

                } else {
                    Thread->Preempted = FALSE;
                }
            }
        }
    }

    //
    // If a thread was scheduled for execution on the current processor,
    // then return the address of the thread with the dispatcher database
    // locked. Otherwise, return NULL with the dispatcher data unlocked.
    //

    NextThread = Prcb->NextThread;
    if (NextThread == NULL) {
        KiUnlockDispatcherDatabase(OldIrql);
    }

    return NextThread;
}
Esempio n. 25
0
LONG
KeSetEvent (
    IN PRKEVENT Event,
    IN KPRIORITY Increment,
    IN BOOLEAN Wait
    )

/*++

Routine Description:

    This function sets the signal state of an event object to Signaled
    and attempts to satisfy as many Waits as possible. The previous
    signal state of the event object is returned as the function value.

Arguments:

    Event - Supplies a pointer to a dispatcher object of type event.

    Increment - Supplies the priority increment that is to be applied
       if setting the event causes a Wait to be satisfied.

    Wait - Supplies a boolean value that signifies whether the call to
       KePulseEvent will be immediately followed by a call to one of the
       kernel Wait functions.

Return Value:

    The previous signal state of the event object.

--*/

{

    KIRQL OldIrql;
    LONG OldState;
    PRKTHREAD Thread;

    ASSERT_EVENT(Event);
    ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);

    //
    // Collect call data.
    //

#if defined(_COLLECT_SET_EVENT_CALLDATA_)

    RECORD_CALL_DATA(&KiSetEventCallData);

#endif

    //
    // Raise IRQL to dispatcher level and lock dispatcher database.
    //

    KiLockDispatcherDatabase(&OldIrql);

    //
    // If the current state of the event object is not Signaled, the set the
    // state of the event object to Signaled, and check for waiters.
    //

    OldState = Event->Header.SignalState;
    Event->Header.SignalState = 1;
    if ((OldState == 0) && (IsListEmpty(&Event->Header.WaitListHead) == FALSE)) {
        KiWaitTest(Event, Increment);
    }

    //
    // If the value of the Wait argument is TRUE, then return to the
    // caller with IRQL raised and the dispatcher database locked. Else
    // release the dispatcher database lock and lower IRQL to its
    // previous value.
    //

    if (Wait != FALSE) {
       Thread = KeGetCurrentThread();
       Thread->WaitNext = Wait;
       Thread->WaitIrql = OldIrql;

    } else {
       KiUnlockDispatcherDatabase(OldIrql);
    }

    //
    // Return previous signal state of event object.
    //

    return OldState;
}
Esempio n. 26
0
BOOLEAN
KeConnectInterrupt (
    IN PKINTERRUPT Interrupt
    )

/*++

Routine Description:

    This function connects an interrupt object to the interrupt vector
    specified by the interrupt object. If the interrupt object is already
    connected, or an attempt is made to connect to an interrupt that cannot
    be connected, then a value of FALSE is returned. Else the specified
    interrupt object is connected to the interrupt vector, the connected
    state is set to TRUE, and TRUE is returned as the function value.

Arguments:

    Interrupt - Supplies a pointer to a control object of type interrupt.

Return Value:

    If the interrupt object is already connected or an attempt is made to
    connect to an interrupt vector that cannot be connected, then a value
    of FALSE is returned. Else a value of TRUE is returned.

--*/

{

    BOOLEAN Connected;
    PKINTERRUPT Interruptx;
    KIRQL Irql;
    CHAR Number;
    KIRQL OldIrql;
    KIRQL PreviousIrql;
    ULONG Vector;

    //
    // If the interrupt object is already connected, the interrupt vector
    // number is invalid, an attempt is being made to connect to a vector
    // that cannot be connected, the interrupt request level is invalid,
    // the processor number is invalid, of the interrupt vector is less
    // than or equal to the highest level and it not equal to the specified
    // IRQL, then do not connect the interrupt object. Else connect interrupt
    // object to the specified vector and establish the proper interrupt
    // dispatcher.
    //

    Connected = FALSE;
    Irql = Interrupt->Irql;
    Number = Interrupt->Number;
    Vector = Interrupt->Vector;
    if (
        (Vector < MAXIMUM_VECTOR) &&            // will fit in interrupt table
        (Irql <= HIGH_LEVEL) &&                 // is at a reasonable priority
        (Number < KeNumberProcessors) &&        // can run on a cpu we have
        (
            (Vector > HIGH_LEVEL) ||            // and is either EISA or
            ((PCR->ReservedVectors & (1 << Vector)) == 0) // is NOT reserved
        )
    ) {

        //
        //
        // Set system affinity to the specified processor.
        //

        KeSetSystemAffinityThread((KAFFINITY)(1 << Number));

        //
        // Raise IRQL to dispatcher level and lock dispatcher database.
        //

        KiLockDispatcherDatabase(&OldIrql);

        //
        // If the specified interrupt vector is not connected, then
        // connect the interrupt vector to the interrupt dispatcher
        // and set the new interrupt mode and enable masks.
        // Else if the interrupt is
        // already chained, then add the new interrupt object at the end
        // of the chain. If the interrupt vector is not chained, then
        // start a chain with the previous interrupt object at the front
        // of the chain. The interrupt mode of all interrupt objects in
        // a chain must be the same.
        //

        if (Interrupt->Connected == FALSE) {
            if (PCR->InterruptRoutine[Vector] ==
                (PKINTERRUPT_ROUTINE)(&KxUnexpectedInterrupt.DispatchCode)) {
                Connected = TRUE;
                Interrupt->Connected = TRUE;
                if (Interrupt->FloatingSave) {
                    Interrupt->DispatchAddress = KiFloatingDispatch;

                } else {
                    if (Interrupt->Irql == Interrupt->SynchronizeIrql) {
#if defined(NT_UP)
                        Interrupt->DispatchAddress =
                                 (PKINTERRUPT_ROUTINE)Interrupt->ServiceRoutine;
#else
                        Interrupt->DispatchAddress =
                                 (PKINTERRUPT_ROUTINE)KiInterruptDispatchSame;
#endif

                    } else {
                        Interrupt->DispatchAddress =
                                 (PKINTERRUPT_ROUTINE)KiInterruptDispatchRaise;
                    }
                }

                //
                // Copy the function descriptor for the Dispatch routine
                // into DispatchCode.  This will be used by KiInterruptEx-
                // ception to dispatch the interrupt.
                //

                Interrupt->DispatchCode[0] =
                                *(PULONG)(Interrupt->DispatchAddress);
                Interrupt->DispatchCode[1] =
                                *(((PULONG)(Interrupt->DispatchAddress))+1);
                PCR->InterruptRoutine[Vector] =
                            (PKINTERRUPT_ROUTINE)Interrupt->DispatchCode;

                HalEnableSystemInterrupt(Vector, Irql, Interrupt->Mode);

            } else if (Interrupt->ShareVector) {
                Interruptx = CONTAINING_RECORD(PCR->InterruptRoutine[Vector],
                                               KINTERRUPT,
                                               DispatchCode[0]);
                if (Interruptx->ShareVector &&
                    Interrupt->Mode == Interruptx->Mode) {
                    Connected = TRUE;
                    Interrupt->Connected = TRUE;
                    KeRaiseIrql((KIRQL)(max(Irql, SYNCH_LEVEL)), &PreviousIrql);
                    if (Interruptx->DispatchAddress !=
                                    (PKINTERRUPT_ROUTINE)KiChainedDispatch) {
                        InitializeListHead(&Interruptx->InterruptListEntry);
                        Interruptx->DispatchAddress =
                                        (PKINTERRUPT_ROUTINE)KiChainedDispatch;
                        Interruptx->DispatchCode[0] =
                                        *(PULONG)KiChainedDispatch;
                        Interruptx->DispatchCode[1] =
                                        *(((PULONG)KiChainedDispatch)+1);
                    }

                    InsertTailList(&Interruptx->InterruptListEntry,
                                   &Interrupt->InterruptListEntry);
                    KeLowerIrql(PreviousIrql);
                }
            }
        }

        //
        // Unlock dispatcher database and lower IRQL to its previous value.
        //

        KiUnlockDispatcherDatabase(OldIrql);

        //
        // Set system affinity back to the original value.
        //

        KeRevertToUserAffinityThread();
    }

    //
    // Return whether interrupt was connected to the specified vector.
    //

    return Connected;
}
Esempio n. 27
0
BOOLEAN
KeDisconnectInterrupt (
    __inout PKINTERRUPT Interrupt
    )

/*++

Routine Description:

    This function disconnects an interrupt object from the interrupt vector
    specified by the interrupt object. If the interrupt object is not
    connected, then a value of FALSE is returned. Else the specified interrupt
    object is disconnected from the interrupt vector, the connected state is
    set to FALSE, and TRUE is returned as the function value.

Arguments:

    Interrupt - Supplies a pointer to a control object of type interrupt.

Return Value:

    If the interrupt object is not connected, then a value of FALSE is
    returned. Else a value of TRUE is returned.

--*/

{

    DISPATCH_INFO DispatchInfo;
    BOOLEAN Connected;
    PKINTERRUPT Interrupty;
    KIRQL Irql;
    KIRQL OldIrql;
    ULONG Vector;

    //
    // Set system affinity to the specified processor.
    //

    KeSetSystemAffinityThread((KAFFINITY)(1<<Interrupt->Number));

    //
    // Raise IRQL to dispatcher level and lock dispatcher database.
    //

    KiLockDispatcherDatabase(&OldIrql);

    //
    // If the interrupt object is connected, then disconnect it from the
    // specified vector.
    //

    Connected = Interrupt->Connected;
    if (Connected) {
        Irql = Interrupt->Irql;
        Vector = Interrupt->Vector;

        //
        // If the specified interrupt vector is not connected to the chained
        // interrupt dispatcher, then disconnect it by setting its dispatch
        // address to the unexpected interrupt routine. Else remove the
        // interrupt object from the interrupt chain. If there is only
        // one entry remaining in the list, then reestablish the dispatch
        // address.
        //

        //
        // Determine interrupt dispatch vector
        //

        KiGetVectorInfo (
            Vector,
            &DispatchInfo
            );


        //
        // Is dispatch a chained handler?
        //

        if (DispatchInfo.Type == ChainConnect) {

            ASSERT (Irql <= SYNCH_LEVEL);

            //
            // Is interrupt being removed from head?
            //

            if (Interrupt == DispatchInfo.Interrupt) {

                //
                // Update next interrupt object to be head
                //

                DispatchInfo.Interrupt = CONTAINING_RECORD(
                                               DispatchInfo.Interrupt->InterruptListEntry.Flink,
                                               KINTERRUPT,
                                               InterruptListEntry
                                               );

                KiConnectVectorAndInterruptObject (DispatchInfo.Interrupt, ChainConnect);
            }

            //
            // Remove interrupt object
            //

            RemoveEntryList(&Interrupt->InterruptListEntry);

            //
            // If there's only one interrupt object left on this vector,
            // determine proper interrupt dispatcher
            //

            Interrupty = CONTAINING_RECORD(
                                DispatchInfo.Interrupt->InterruptListEntry.Flink,
                                KINTERRUPT,
                                InterruptListEntry
                                );

            if (DispatchInfo.Interrupt == Interrupty) {
                KiConnectVectorAndInterruptObject (Interrupty, NormalConnect);
            }

        } else {

            //
            // Removing last interrupt object from the vector.  Disable the
            // vector, and set it to unconnected
            //

            HalDisableSystemInterrupt(Interrupt->Vector, Irql);
            KiConnectVectorAndInterruptObject (Interrupt, NoConnect);
        }


        KeSweepIcache(TRUE);
        Interrupt->Connected = FALSE;
    }

    //
    // Unlock dispatcher database and lower IRQL to its previous value.
    //

    KiUnlockDispatcherDatabase(OldIrql);

    //
    // Set system affinity back to the original value.
    //

    KeRevertToUserAffinityThread();

    //
    // Return whether interrupt was disconnected from the specified vector.
    //

    return Connected;
}
Esempio n. 28
0
BOOLEAN
KeDisconnectInterrupt (
    IN PKINTERRUPT Interrupt
    )

/*++

Routine Description:

    This function disconnects an interrupt object from the interrupt vector
    specified by the interrupt object. If the interrupt object is not
    connected, then a value of FALSE is returned. Else the specified interrupt
    object is disconnected from the interrupt vector, the connected state is
    set to FALSE, and TRUE is returned as the function value.

Arguments:

    Interrupt - Supplies a pointer to a control object of type interrupt.

Return Value:

    If the interrupt object is not connected, then a value of FALSE is
    returned. Else a value of TRUE is returned.

--*/

{

    BOOLEAN Connected;
    PKINTERRUPT Interruptx;
    PKINTERRUPT Interrupty;
    KIRQL Irql;
    KIRQL OldIrql;
    KIRQL PreviousIrql;
    ULONG Vector;

    //
    // Set system affinity to the specified processor.
    //

    KeSetSystemAffinityThread((KAFFINITY)(1 << Interrupt->Number));

    //
    // Raise IRQL to dispatcher level and lock dispatcher database.
    //

    KiLockDispatcherDatabase(&OldIrql);

    //
    // If the interrupt object is connected, then disconnect it from the
    // specified vector.
    //

    Connected = Interrupt->Connected;
    if (Connected != FALSE) {
        Irql = Interrupt->Irql;
        Vector = Interrupt->Vector;

        //
        // If the specified interrupt vector is not connected to the chained
        // interrupt dispatcher, then disconnect it by setting its dispatch
        // address to the unexpected interrupt routine. Else remove the
        // interrupt object from the interrupt chain. If there is only
        // one entry remaining in the list, then reestablish the dispatch
        // address.
        //

        Interruptx = CONTAINING_RECORD(PCR->InterruptRoutine[Vector],
                                       KINTERRUPT,
                                       DispatchCode[0]);

        if (Interruptx->DispatchAddress ==
                                (PKINTERRUPT_ROUTINE)KiChainedDispatch) {
            KeRaiseIrql((KIRQL)(max(Irql, SYNCH_LEVEL)), &PreviousIrql);
            if (Interrupt == Interruptx) {
                Interruptx = CONTAINING_RECORD(Interruptx->InterruptListEntry.Flink,
                                               KINTERRUPT, InterruptListEntry);
                Interruptx->DispatchAddress =
                                (PKINTERRUPT_ROUTINE)KiChainedDispatch;
                Interruptx->DispatchCode[0] = *(PULONG)KiChainedDispatch;
                Interruptx->DispatchCode[1] = *(((PULONG)KiChainedDispatch)+1);
                PCR->InterruptRoutine[Vector] =
                                (PKINTERRUPT_ROUTINE)Interruptx->DispatchCode;

            }

            RemoveEntryList(&Interrupt->InterruptListEntry);
            Interrupty = CONTAINING_RECORD(Interruptx->InterruptListEntry.Flink,
                                           KINTERRUPT,
                                           InterruptListEntry);

            if (Interruptx == Interrupty) {
                if (Interrupt->FloatingSave) {
                    Interrupt->DispatchAddress = KiFloatingDispatch;

                } else {
                    if (Interrupt->Irql == Interrupt->SynchronizeIrql) {
#if defined(NT_UP)
                        Interrupt->DispatchAddress =
                                 (PKINTERRUPT_ROUTINE)Interrupt->ServiceRoutine;
#else
                        Interrupt->DispatchAddress =
                                 (PKINTERRUPT_ROUTINE)KiInterruptDispatchSame;
#endif

                    } else {
                        Interrupt->DispatchAddress =
                                 (PKINTERRUPT_ROUTINE)KiInterruptDispatchRaise;
                    }
                }

                //
                // Copy the function descriptor for the Dispatch routine
                // into DispatchCode.  This will be used by KiInterruptEx-
                // ception to dispatch the interrupt.
                //
                Interrupty->DispatchCode[0] =
                                *(PULONG)(Interrupty->DispatchAddress);
                Interrupty->DispatchCode[1] =
                                *(((PULONG)(Interrupty->DispatchAddress))+1);
                PCR->InterruptRoutine[Vector] =
                               (PKINTERRUPT_ROUTINE)Interrupty->DispatchCode;

                }

            KeLowerIrql(PreviousIrql);

        } else {
            HalDisableSystemInterrupt(Vector, Irql);
            PCR->InterruptRoutine[Vector] =
                    (PKINTERRUPT_ROUTINE)(&KxUnexpectedInterrupt.DispatchCode);
        }
#ifdef NOTDEF
        KeSweepIcache(TRUE);
#endif
        Interrupt->Connected = FALSE;
    }

    //
    // Unlock dispatcher database and lower IRQL to its previous value.
    //

    KiUnlockDispatcherDatabase(OldIrql);

    //
    // Set system affinity back to the original value.
    //

    KeRevertToUserAffinityThread();

    //
    // Return whether interrupt was disconnected from the specified vector.
    //

    return Connected;
}
Esempio n. 29
0
LONG
KeReleaseSemaphore (
    IN PRKSEMAPHORE Semaphore,
    IN KPRIORITY Increment,
    IN LONG Adjustment,
    IN BOOLEAN Wait
    )

/*++

Routine Description:

    This function releases a semaphore by adding the specified adjustment
    value to the current semaphore count and attempts to satisfy as many
    Waits as possible. The previous signal state of the semaphore object
    is returned as the function value.

Arguments:

    Semaphore - Supplies a pointer to a dispatcher object of type
        semaphore.

    Increment - Supplies the priority increment that is to be applied
        if releasing the semaphore causes a Wait to be satisfied.

    Adjustment - Supplies value that is to be added to the current
        semaphore count.

    Wait - Supplies a boolean value that signifies whether the call to
        KeReleaseSemaphore will be immediately followed by a call to one
        of the kernel Wait functions.

Return Value:

    The previous signal state of the semaphore object.

--*/

{

    LONG NewState;
    KIRQL OldIrql;
    LONG OldState;
    PRKTHREAD Thread;

    ASSERT_SEMAPHORE( Semaphore );
    ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);

    //
    // Raise IRQL to dispatcher level and lock dispatcher database.
    //

    KiLockDispatcherDatabase(&OldIrql);

    //
    // Capture the current signal state of the semaphore object and
    // compute the new count value.
    //

    OldState = Semaphore->Header.SignalState;
    NewState = OldState + Adjustment;

    //
    // If the new state value is greater than the limit or a carry occurs,
    // then unlock the dispatcher database, and raise an exception.
    //

    if ((NewState > Semaphore->Limit) || (NewState < OldState)) {
        KiUnlockDispatcherDatabase(OldIrql);
        ExRaiseStatus(STATUS_SEMAPHORE_LIMIT_EXCEEDED);
    }

    //
    // Set the new signal state of the semaphore object and set the wait
    // next value. If the previous signal state was Not-Signaled (i.e.
    // the count was zero), and the wait queue is not empty, then attempt
    // to satisfy as many Waits as possible.
    //

    Semaphore->Header.SignalState = NewState;
    if ((OldState == 0) && (IsListEmpty(&Semaphore->Header.WaitListHead) == FALSE)) {
        KiWaitTest(Semaphore, Increment);
    }

    //
    // If the value of the Wait argument is TRUE, then return to the
    // caller with IRQL raised and the dispatcher database locked. Else
    // release the dispatcher database lock and lower IRQL to its
    // previous value.
    //

    if (Wait != FALSE) {
        Thread = KeGetCurrentThread();
        Thread->WaitNext = Wait;
        Thread->WaitIrql = OldIrql;

    } else {
        KiUnlockDispatcherDatabase(OldIrql);
    }

    //
    // Return previous signal state of sempahore object.
    //

    return OldState;
}
Esempio n. 30
0
NTSTATUS
KeWaitForMultipleObjects (
    IN ULONG Count,
    IN PVOID Object[],
    IN WAIT_TYPE WaitType,
    IN KWAIT_REASON WaitReason,
    IN KPROCESSOR_MODE WaitMode,
    IN BOOLEAN Alertable,
    IN PLARGE_INTEGER Timeout OPTIONAL,
    IN PKWAIT_BLOCK WaitBlockArray OPTIONAL
    )

/*++

Routine Description:

    This function waits until the specified objects attain a state of
    Signaled. The wait can be specified to wait until all of the objects
    attain a state of Signaled or until one of the objects attains a state
    of Signaled. An optional timeout can also be specified. If a timeout
    is not specified, then the wait will not be satisfied until the objects
    attain a state of Signaled. If a timeout is specified, and the objects
    have not attained a state of Signaled when the timeout expires, then
    the wait is automatically satisfied. If an explicit timeout value of
    zero is specified, then no wait will occur if the wait cannot be satisfied
    immediately. The wait can also be specified as alertable.

Arguments:

    Count - Supplies a count of the number of objects that are to be waited
        on.

    Object[] - Supplies an array of pointers to dispatcher objects.

    WaitType - Supplies the type of wait to perform (WaitAll, WaitAny).

    WaitReason - Supplies the reason for the wait.

    WaitMode  - Supplies the processor mode in which the wait is to occur.

    Alertable - Supplies a boolean value that specifies whether the wait is
        alertable.

    Timeout - Supplies a pointer to an optional absolute of relative time over
        which the wait is to occur.

    WaitBlockArray - Supplies an optional pointer to an array of wait blocks
        that are to used to describe the wait operation.

Return Value:

    The wait completion status. A value of STATUS_TIMEOUT is returned if a
    timeout occurred. The index of the object (zero based) in the object
    pointer array is returned if an object satisfied the wait. A value of
    STATUS_ALERTED is returned if the wait was aborted to deliver an alert
    to the current thread. A value of STATUS_USER_APC is returned if the
    wait was aborted to deliver a user APC to the current thread.

--*/

{

    LARGE_INTEGER DueTime;
    ULONG Index;
    LARGE_INTEGER NewTime;
    PRKTHREAD NextThread;
    PKMUTANT Objectx;
    PLARGE_INTEGER OriginalTime;
    PRKQUEUE Queue;
    PRKTHREAD Thread;
    PRKTIMER Timer;
    PRKWAIT_BLOCK WaitBlock;
    BOOLEAN WaitSatisfied;
    NTSTATUS WaitStatus;
    PKWAIT_BLOCK WaitTimer;

    //
    // If the dispatcher database lock is not already held, then set the wait
    // IRQL and lock the dispatcher database. Else set boolean wait variable
    // to FALSE.
    //

    Thread = KeGetCurrentThread();
    if (Thread->WaitNext) {
        Thread->WaitNext = FALSE;

    } else {
        KiLockDispatcherDatabase(&Thread->WaitIrql);
    }

    //
    // If a wait block array has been specified, then the maximum number of
    // objects that can be waited on is specified by MAXIMUM_WAIT_OBJECTS.
    // Otherwise the builtin wait blocks in the thread object are used and
    // the maximum number of objects that can be waited on is specified by
    // THREAD_WAIT_OBJECTS. If the specified number of objects is not within
    // limits, then bug check.
    //

    if (ARGUMENT_PRESENT(WaitBlockArray)) {
        if (Count > MAXIMUM_WAIT_OBJECTS) {
            KeBugCheck(MAXIMUM_WAIT_OBJECTS_EXCEEDED);
        }

    } else {
        if (Count > THREAD_WAIT_OBJECTS) {
            KeBugCheck(MAXIMUM_WAIT_OBJECTS_EXCEEDED);
        }

        WaitBlockArray = &Thread->WaitBlock[0];
    }

    //
    // Start of wait loop.
    //
    // Note this loop is repeated if a kernel APC is delivered in the middle
    // of the wait or a kernel APC is pending on the first attempt through
    // the loop.
    //

    OriginalTime = Timeout;
    do {

        //
        // Set address of wait block list in thread object.
        //

        Thread->WaitBlockList = WaitBlockArray;

        //
        // Test to determine if a kernel APC is pending.
        //
        // If a kernel APC is pending and the previous IRQL was less than
        // APC_LEVEL, then a kernel APC was queued by another processor just
        // after IRQL was raised to DISPATCH_LEVEL, but before the dispatcher
        // database was locked.
        //
        // N.B. that this can only happen in a multiprocessor system.
        //

        if (Thread->ApcState.KernelApcPending && (Thread->WaitIrql < APC_LEVEL)) {

            //
            // Unlock the dispatcher database and lower IRQL to its previous
            // value. An APC interrupt will immediately occur which will result
            // in the delivery of the kernel APC if possible.
            //

            KiUnlockDispatcherDatabase(Thread->WaitIrql);

        } else {

            //
            // Construct wait blocks and check to determine if the wait is
            // already satisfied. If the wait is satisfied, then perform
            // wait completion and return. Else put current thread in a wait
            // state if an explicit timeout value of zero is not specified.
            //

            Thread->WaitStatus = (NTSTATUS)0;
            WaitSatisfied = TRUE;
            for (Index = 0; Index < Count; Index += 1) {

                //
                // Test if wait can be satisfied immediately.
                //

                Objectx = (PKMUTANT)Object[Index];

                ASSERT(Objectx->Header.Type != QueueObject);

                if (WaitType == WaitAny) {

                    //
                    // If the object is a mutant object and the mutant object
                    // has been recursively acquired MINLONG times, then raise
                    // an exception. Otherwise if the signal state of the mutant
                    // object is greater than zero, or the current thread is
                    // the owner of the mutant object, then satisfy the wait.
                    //

                    if (Objectx->Header.Type == MutantObject) {
                        if ((Objectx->Header.SignalState > 0) ||
                            (Thread == Objectx->OwnerThread)) {
                            if (Objectx->Header.SignalState != MINLONG) {
                                KiWaitSatisfyMutant(Objectx, Thread);
                                WaitStatus = (NTSTATUS)(Index | Thread->WaitStatus);
                                goto NoWait;

                            } else {
                                KiUnlockDispatcherDatabase(Thread->WaitIrql);
                                ExRaiseStatus(STATUS_MUTANT_LIMIT_EXCEEDED);
                            }
                        }

                    //
                    // If the signal state is greater than zero, then satisfy
                    // the wait.
                    //

                    } else if (Objectx->Header.SignalState > 0) {
                        KiWaitSatisfyOther(Objectx);
                        WaitStatus = (NTSTATUS)(Index);
                        goto NoWait;
                    }

                } else {

                    //
                    // If the object is a mutant object and the mutant object
                    // has been recursively acquired MAXLONG times, then raise
                    // an exception. Otherwise if the signal state of the mutant
                    // object is less than or equal to zero and the current
                    // thread is not the  owner of the mutant object, then the
                    // wait cannot be satisfied.
                    //

                    if (Objectx->Header.Type == MutantObject) {
                        if ((Thread == Objectx->OwnerThread) &&
                            (Objectx->Header.SignalState == MINLONG)) {
                            KiUnlockDispatcherDatabase(Thread->WaitIrql);
                            ExRaiseStatus(STATUS_MUTANT_LIMIT_EXCEEDED);

                        } else if ((Objectx->Header.SignalState <= 0) &&
                                  (Thread != Objectx->OwnerThread)) {
                            WaitSatisfied = FALSE;
                        }

                    //
                    // If the signal state is less than or equal to zero, then
                    // the wait cannot be satisfied.
                    //

                    } else if (Objectx->Header.SignalState <= 0) {
                        WaitSatisfied = FALSE;
                    }
                }

                //
                // Construct wait block for the current object.
                //

                WaitBlock = &WaitBlockArray[Index];
                WaitBlock->Object = (PVOID)Objectx;
                WaitBlock->WaitKey = (CSHORT)(Index);
                WaitBlock->WaitType = (USHORT)WaitType;
                WaitBlock->Thread = Thread;
                WaitBlock->NextWaitBlock = &WaitBlockArray[Index + 1];
            }

            //
            // If the wait type is wait all, then check to determine if the
            // wait can be satisfied immediately.
            //

            if ((WaitType == WaitAll) && (WaitSatisfied)) {
                WaitBlock->NextWaitBlock = &WaitBlockArray[0];
                KiWaitSatisfyAll(WaitBlock);
                WaitStatus = (NTSTATUS)Thread->WaitStatus;
                goto NoWait;
            }

            //
            // Test for alert pending.
            //

            TestForAlertPending(Alertable);

            //
            // The wait cannot be satisifed immediately. Check to determine if
            // a timeout value is specified.
            //

            if (ARGUMENT_PRESENT(Timeout)) {

                //
                // If the timeout value is zero, then return immediately without
                // waiting.
                //

                if (!(Timeout->LowPart | Timeout->HighPart)) {
                    WaitStatus = (NTSTATUS)(STATUS_TIMEOUT);
                    goto NoWait;
                }

                //
                // Initialize a wait block for the thread specific timer,
                // initialize timer wait list head, insert the timer in the
                // timer tree, and increment the number of wait objects.
                //
                // N.B. The timer wait block is initialized when the respective
                //      thread is initialized. Thus the constant fields are not
                //      reinitialized. These include the wait object, wait key,
                //      wait type, and the wait list entry link pointers.
                //

                WaitTimer = &Thread->WaitBlock[TIMER_WAIT_BLOCK];
                WaitBlock->NextWaitBlock = WaitTimer;
                WaitBlock = WaitTimer;
                Timer = &Thread->Timer;
                InitializeListHead(&Timer->Header.WaitListHead);
                if (KiInsertTreeTimer(Timer, *Timeout) == FALSE) {
                    WaitStatus = (NTSTATUS)STATUS_TIMEOUT;
                    goto NoWait;
                }

                DueTime.QuadPart = Timer->DueTime.QuadPart;
            }

            //
            // Close up the circular list of wait control blocks.
            //

            WaitBlock->NextWaitBlock = &WaitBlockArray[0];

            //
            // Insert wait blocks in object wait lists.
            //

            WaitBlock = &WaitBlockArray[0];
            do {
                Objectx = (PKMUTANT)WaitBlock->Object;
                InsertTailList(&Objectx->Header.WaitListHead, &WaitBlock->WaitListEntry);
                WaitBlock = WaitBlock->NextWaitBlock;
            } while (WaitBlock != &WaitBlockArray[0]);

            //
            // If the current thread is processing a queue entry, then attempt
            // to activate another thread that is blocked on the queue object.
            //

            Queue = Thread->Queue;
            if (Queue != NULL) {
                KiActivateWaiterQueue(Queue);
            }

            //
            // Set the thread wait parameters, set the thread dispatcher state
            // to Waiting, and insert the thread in the wait list.
            //

            Thread->Alertable = Alertable;
            Thread->WaitMode = WaitMode;
            Thread->WaitReason = (UCHAR)WaitReason;
            Thread->WaitTime= KiQueryLowTickCount();
            Thread->State = Waiting;
            KiInsertWaitList(WaitMode, Thread);

            //
            // Switch context to selected thread.
            //
            // Control is returned at the original IRQL.
            //

            ASSERT(Thread->WaitIrql <= DISPATCH_LEVEL);

            WaitStatus = (NTSTATUS)KiSwapThread();

            //
            // If the thread was not awakened to deliver a kernel mode APC,
            // then the wait status.
            //

            if (WaitStatus != STATUS_KERNEL_APC) {
                return WaitStatus;
            }

            if (ARGUMENT_PRESENT(Timeout)) {

                //
                // Reduce the amount of time remaining before timeout occurs.
                //

                Timeout = KiComputeWaitInterval(OriginalTime,
                                                &DueTime,
                                                &NewTime);
            }
        }

        //
        // Raise IRQL to DISPATCH_LEVEL and lock the dispatcher database.
        //

        KiLockDispatcherDatabase(&Thread->WaitIrql);
    } while (TRUE);

    //
    // The thread is alerted or a user APC should be delivered. Unlock the
    // dispatcher database, lower IRQL to its previous value, and return
    // the wait status.
    //

    KiUnlockDispatcherDatabase(Thread->WaitIrql);
    return WaitStatus;

    //
    // The wait has been satisfied without actually waiting.
    //
    // If the thread priority that is less than time critical, then reduce
    // the thread quantum. If a quantum end occurs, then reduce the thread
    // priority.
    //

NoWait:
    KiAdjustQuantumThread(Thread);

    //
    // Unlock the dispatcher database, lower IRQL to its previous value, and
    // return the wait status.
    //

    KiUnlockDispatcherDatabase(Thread->WaitIrql);
    return WaitStatus;
}