Esempio n. 1
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. 2
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. 3
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;
}