Esempio n. 1
0
VOID FreeTimeouts(PC0C_IO_PORT pIoPort)
{
    KeCancelTimer(&pIoPort->timerReadTotal);
    KeCancelTimer(&pIoPort->timerReadInterval);
    KeCancelTimer(&pIoPort->timerWriteTotal);
    KeCancelTimer(&pIoPort->timerClose);

    KeRemoveQueueDpc(&pIoPort->timerReadTotalDpc);
    KeRemoveQueueDpc(&pIoPort->timerReadIntervalDpc);
    KeRemoveQueueDpc(&pIoPort->timerWriteTotalDpc);
    KeRemoveQueueDpc(&pIoPort->timerCloseDpc);
}
BOOLEAN
FxDpc::Cancel(
    __in BOOLEAN Wait
    )
{
    BOOLEAN result;

    result = KeRemoveQueueDpc(GetDpcPtr());

    //
    // If result == FALSE, then the DPC could already be running.
    //
    // If the caller supplies Wait == TRUE, they want to wait and
    // ensure on return the DPC has finished running.
    //
    // The trick here is to implement this without adding execessive
    // overhead to the "normal" path, such as tracking reference counts,
    // locking, signaling events to waiting threads, etc.
    //
    // So we take the expensive approach for the Cancel call in the
    // case the caller wants to wait, and misses the DPC window. In
    // this case we will just do the system wide FlushQueuedDpc's to
    // ensure the DPC has finished running before return.
    //
    if( Wait && !result ) {

        ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);

        KeFlushQueuedDpcs();
    }

    return result;
}
/**
 * Worker function that stops an active timer.
 *
 * Shared by RTTimerStop and RTTimerDestroy.
 *
 * @param   pTimer      The active timer.
 */
static void rtTimerNtStopWorker(PRTTIMER pTimer)
{
    /*
     * Just cancel the timer, dequeue the DPCs and flush them (if this is supported).
     */
    ASMAtomicWriteBool(&pTimer->fSuspended, true);

    KeCancelTimer(&pTimer->NtTimer);

    for (RTCPUID iCpu = 0; iCpu < pTimer->cSubTimers; iCpu++)
        KeRemoveQueueDpc(&pTimer->aSubTimers[iCpu].NtDpc);
}
Esempio n. 4
0
/**
 * Worker function that stops an active timer.
 *
 * Shared by RTTimerStop and RTTimerDestroy.
 *
 * @param   pTimer      The active timer.
 */
static void rtTimerNtStopWorker(PRTTIMER pTimer)
{
    /*
     * Just cancel the timer, dequeue the DPCs and flush them (if this is supported).
     */
    ASMAtomicWriteBool(&pTimer->fSuspended, true);
    KeCancelTimer(&pTimer->NtTimer);

    for (RTCPUID iCpu = 0; iCpu < pTimer->cSubTimers; iCpu++)
        KeRemoveQueueDpc(&pTimer->aSubTimers[iCpu].NtDpc);

    /*
     * I'm a bit uncertain whether this should be done during RTTimerStop
     * or only in RTTimerDestroy()... Linux and Solaris will wait AFAIK,
     * which is why I'm keeping this here for now.
     */
    if (g_pfnrtNtKeFlushQueuedDpcs)
        g_pfnrtNtKeFlushQueuedDpcs();
}
RTDECL(int) RTMpOnSpecific(RTCPUID idCpu, PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2)
{
    /*
     * Don't try mess with an offline CPU.
     */
    if (!RTMpIsCpuOnline(idCpu))
        return !RTMpIsCpuPossible(idCpu)
              ? VERR_CPU_NOT_FOUND
              : VERR_CPU_OFFLINE;

    /*
     * Use the broadcast IPI routine if there are no more than two CPUs online,
     * or if the current IRQL is unsuitable for KeWaitForSingleObject.
     */
    int rc;
    uint32_t cHits = 0;
    if (   g_pfnrtKeIpiGenericCall
        && (   RTMpGetOnlineCount() <= 2
            || KeGetCurrentIrql()   > APC_LEVEL)
       )
    {
        rc = rtMpCallUsingBroadcastIpi(pfnWorker, pvUser1, pvUser2, rtmpNtOnSpecificBroadcastIpiWrapper,
                                       idCpu, NIL_RTCPUID, &cHits);
        if (RT_SUCCESS(rc))
        {
            if (cHits == 1)
                return VINF_SUCCESS;
            rc = cHits == 0 ? VERR_CPU_OFFLINE : VERR_CPU_IPE_1;
        }
        return rc;
    }

#if 0
    rc = rtMpCallUsingDpcs(pfnWorker, pvUser1, pvUser2, RT_NT_CPUID_SPECIFIC, idCpu, NIL_RTCPUID, &cHits);
    if (RT_SUCCESS(rc))
    {
        if (cHits == 1)
            return VINF_SUCCESS;
        rc = cHits == 0 ? VERR_CPU_OFFLINE : VERR_CPU_IPE_1;
    }
    return rc;

#else
    /*
     * Initialize the argument package and the objects within it.
     * The package is referenced counted to avoid unnecessary spinning to
     * synchronize cleanup and prevent stack corruption.
     */
    PRTMPNTONSPECIFICARGS pArgs = (PRTMPNTONSPECIFICARGS)ExAllocatePoolWithTag(NonPagedPool, sizeof(*pArgs), (ULONG)'RTMp');
    if (!pArgs)
        return VERR_NO_MEMORY;
    pArgs->cRefs                  = 2;
    pArgs->fExecuting             = false;
    pArgs->fDone                  = false;
    pArgs->CallbackArgs.pfnWorker = pfnWorker;
    pArgs->CallbackArgs.pvUser1   = pvUser1;
    pArgs->CallbackArgs.pvUser2   = pvUser2;
    pArgs->CallbackArgs.idCpu     = idCpu;
    pArgs->CallbackArgs.cHits     = 0;
    pArgs->CallbackArgs.cRefs     = 2;
    KeInitializeEvent(&pArgs->DoneEvt, SynchronizationEvent, FALSE /* not signalled */);
    KeInitializeDpc(&pArgs->Dpc, rtMpNtOnSpecificDpcWrapper, pArgs);
    KeSetImportanceDpc(&pArgs->Dpc, HighImportance);
    KeSetTargetProcessorDpc(&pArgs->Dpc, (int)idCpu);

    /*
     * Disable preemption while we check the current processor and inserts the DPC.
     */
    KIRQL bOldIrql;
    KeRaiseIrql(DISPATCH_LEVEL, &bOldIrql);
    ASMCompilerBarrier(); /* paranoia */

    if (RTMpCpuId() == idCpu)
    {
        /* Just execute the callback on the current CPU. */
        pfnWorker(idCpu, pvUser1, pvUser2);
        KeLowerIrql(bOldIrql);

        ExFreePool(pArgs);
        return VINF_SUCCESS;
    }

    /* Different CPU, so queue it if the CPU is still online. */
    if (RTMpIsCpuOnline(idCpu))
    {
        BOOLEAN fRc = KeInsertQueueDpc(&pArgs->Dpc, 0, 0);
        Assert(fRc);
        KeLowerIrql(bOldIrql);

        uint64_t const nsRealWaitTS = RTTimeNanoTS();

        /*
         * Wait actively for a while in case the CPU/thread responds quickly.
         */
        uint32_t cLoopsLeft = 0x20000;
        while (cLoopsLeft-- > 0)
        {
            if (pArgs->fDone)
            {
                rtMpNtOnSpecificRelease(pArgs);
                return VINF_SUCCESS;
            }
            ASMNopPause();
        }

        /*
         * It didn't respond, so wait on the event object, poking the CPU if it's slow.
         */
        LARGE_INTEGER Timeout;
        Timeout.QuadPart = -10000; /* 1ms */
        NTSTATUS rcNt = KeWaitForSingleObject(&pArgs->DoneEvt, Executive, KernelMode, FALSE /* Alertable */, &Timeout);
        if (rcNt == STATUS_SUCCESS)
        {
            rtMpNtOnSpecificRelease(pArgs);
            return VINF_SUCCESS;
        }

        /* If it hasn't respondend yet, maybe poke it and wait some more. */
        if (rcNt == STATUS_TIMEOUT)
        {
#ifndef IPRT_TARGET_NT4
            if (   !pArgs->fExecuting
                && (   g_pfnrtMpPokeCpuWorker == rtMpPokeCpuUsingHalSendSoftwareInterrupt
                    || g_pfnrtMpPokeCpuWorker == rtMpPokeCpuUsingHalReqestIpiW7Plus
                    || g_pfnrtMpPokeCpuWorker == rtMpPokeCpuUsingHalReqestIpiPreW7))
                RTMpPokeCpu(idCpu);
#endif

            Timeout.QuadPart = -1280000; /* 128ms */
            rcNt = KeWaitForSingleObject(&pArgs->DoneEvt, Executive, KernelMode, FALSE /* Alertable */, &Timeout);
            if (rcNt == STATUS_SUCCESS)
            {
                rtMpNtOnSpecificRelease(pArgs);
                return VINF_SUCCESS;
            }
        }

        /*
         * Something weird is happening, try bail out.
         */
        if (KeRemoveQueueDpc(&pArgs->Dpc))
        {
            ExFreePool(pArgs); /* DPC was still queued, so we can return without further ado. */
            LogRel(("RTMpOnSpecific(%#x): Not processed after %llu ns: rcNt=%#x\n", idCpu, RTTimeNanoTS() - nsRealWaitTS, rcNt));
        }
        else
        {
            /* DPC is running, wait a good while for it to complete. */
            LogRel(("RTMpOnSpecific(%#x): Still running after %llu ns: rcNt=%#x\n", idCpu, RTTimeNanoTS() - nsRealWaitTS, rcNt));

            Timeout.QuadPart = -30*1000*1000*10; /* 30 seconds */
            rcNt = KeWaitForSingleObject(&pArgs->DoneEvt, Executive, KernelMode, FALSE /* Alertable */, &Timeout);
            if (rcNt != STATUS_SUCCESS)
                LogRel(("RTMpOnSpecific(%#x): Giving up on running worker after %llu ns: rcNt=%#x\n", idCpu, RTTimeNanoTS() - nsRealWaitTS, rcNt));
        }
        rc = RTErrConvertFromNtStatus(rcNt);
    }
    else
    {
        /* CPU is offline.*/
        KeLowerIrql(bOldIrql);
        rc = !RTMpIsCpuPossible(idCpu) ? VERR_CPU_NOT_FOUND : VERR_CPU_OFFLINE;
    }

    rtMpNtOnSpecificRelease(pArgs);
    return rc;
#endif
}
Esempio n. 6
0
NTSTATUS
NdFatCommonFlushBuffers (
    IN PIRP_CONTEXT IrpContext,
    IN PIRP Irp
    )

/*++

Routine Description:

    This is the common routine for flushing a buffer.

Arguments:

    Irp - Supplies the Irp to process

Return Value:

    NTSTATUS - The return status for the operation

--*/

{
    NTSTATUS Status;

    PIO_STACK_LOCATION IrpSp;

    PFILE_OBJECT FileObject;

    TYPE_OF_OPEN TypeOfOpen;
    PVCB Vcb;
    PFCB Fcb;
    PCCB Ccb;

    BOOLEAN VcbAcquired = FALSE;
    BOOLEAN FcbAcquired = FALSE;

    PDIRENT Dirent;
    PBCB DirentBcb = NULL;

	PVOLUME_DEVICE_OBJECT		volDo = CONTAINING_RECORD( IrpContext->Vcb, VOLUME_DEVICE_OBJECT, Vcb );
	BOOLEAN						secondarySessionResourceAcquired = FALSE;

	PSECONDARY_REQUEST			secondaryRequest = NULL;

	PNDFS_REQUEST_HEADER		ndfsRequestHeader;
	PNDFS_WINXP_REQUEST_HEADER	ndfsWinxpRequestHeader;
	PNDFS_WINXP_REPLY_HEADER	ndfsWinxpReplytHeader;

	LARGE_INTEGER				timeOut;



    PAGED_CODE();

    IrpSp = IoGetCurrentIrpStackLocation( Irp );

    DebugTrace(+1, Dbg, "FatCommonFlushBuffers\n", 0);
    DebugTrace( 0, Dbg, "Irp           = %08lx\n", Irp);
    DebugTrace( 0, Dbg, "->FileObject  = %08lx\n", IrpSp->FileObject);

	
	//
    //  Extract and decode the file object
    //

    FileObject = IrpSp->FileObject;
    TypeOfOpen = FatDecodeFileObject( FileObject, &Vcb, &Fcb, &Ccb );

    //
    //  CcFlushCache is always synchronous, so if we can't wait enqueue
    //  the irp to the Fsp.
    //

    if ( !FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) ) {

        Status = FatFsdPostRequest( IrpContext, Irp );

        DebugTrace(-1, Dbg, "FatCommonFlushBuffers -> %08lx\n", Status );
        return Status;
    }

    Status = STATUS_SUCCESS;

    try {

		if (!FlagOn(Ccb->NdFatFlags, ND_FAT_CCB_FLAG_UNOPENED)) {

			do {
			
				secondarySessionResourceAcquired 
					= SecondaryAcquireResourceExclusiveLite( IrpContext, 
															 &volDo->Secondary->SessionResource, 
															 BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) );

				if (FlagOn(volDo->Secondary->Thread.Flags, SECONDARY_THREAD_FLAG_REMOTE_DISCONNECTED) ) {

					PrintIrp( Dbg2, "SECONDARY_THREAD_FLAG_REMOTE_DISCONNECTED", NULL, IrpContext->OriginatingIrp );
					FatRaiseStatus( IrpContext, STATUS_CANT_WAIT );	
				}

				secondaryRequest = ALLOC_WINXP_SECONDARY_REQUEST( volDo->Secondary, IRP_MJ_FLUSH_BUFFERS, 0 );

				if (secondaryRequest == NULL) {
	
					Status = STATUS_INSUFFICIENT_RESOURCES;
					break;
				}

				ndfsRequestHeader = &secondaryRequest->NdfsRequestHeader;

				INITIALIZE_NDFS_REQUEST_HEADER( ndfsRequestHeader, NDFS_COMMAND_EXECUTE, volDo->Secondary, IRP_MJ_FLUSH_BUFFERS, 0 );

				ndfsWinxpRequestHeader = (PNDFS_WINXP_REQUEST_HEADER)(ndfsRequestHeader+1);
				ASSERT( ndfsWinxpRequestHeader == (PNDFS_WINXP_REQUEST_HEADER)secondaryRequest->NdfsRequestData );

				INITIALIZE_NDFS_WINXP_REQUEST_HEADER( ndfsWinxpRequestHeader, 
													  IrpContext->OriginatingIrp, 
													  IoGetCurrentIrpStackLocation(IrpContext->OriginatingIrp), 
													  Ccb->PrimaryFileHandle );
				
				ASSERT( !ExIsResourceAcquiredSharedLite(&IrpContext->Vcb->Resource) );	

				secondaryRequest->RequestType = SECONDARY_REQ_SEND_MESSAGE;
				QueueingSecondaryRequest( volDo->Secondary, secondaryRequest );

				timeOut.QuadPart = -NDFAT_TIME_OUT;		
				Status = KeWaitForSingleObject( &secondaryRequest->CompleteEvent, Executive, KernelMode, FALSE, &timeOut );
			
				if (Status != STATUS_SUCCESS) {

					ASSERT( NDFAT_BUG );
					break;
				}

				KeClearEvent (&secondaryRequest->CompleteEvent);

				if (BooleanFlagOn(volDo->Secondary->Thread.Flags, SECONDARY_THREAD_FLAG_REMOTE_DISCONNECTED)) {

					FatRaiseStatus( IrpContext, STATUS_CANT_WAIT );
				}

				if (secondaryRequest->ExecuteStatus == STATUS_SUCCESS) {

					ndfsWinxpReplytHeader = (PNDFS_WINXP_REPLY_HEADER)secondaryRequest->NdfsReplyData;
					ASSERT(ndfsWinxpReplytHeader->Status == STATUS_SUCCESS);
				}

				if (secondaryRequest) {

					DereferenceSecondaryRequest( secondaryRequest );
					secondaryRequest = NULL;
				}

				if ( secondarySessionResourceAcquired == TRUE ) {
					
					SecondaryReleaseResourceLite( IrpContext, &volDo->Secondary->SessionResource );		
					secondarySessionResourceAcquired = FALSE;
				}

				break;

			} while(0);
		} 

		Status = STATUS_SUCCESS;

        //
        //  Case on the type of open that we are trying to flush
        //

        switch (TypeOfOpen) {

        case VirtualVolumeFile:
        case EaFile:
        case DirectoryFile:

            DebugTrace(0, Dbg, "Flush that does nothing\n", 0);
            break;

        case UserFileOpen:

            DebugTrace(0, Dbg, "Flush User File Open\n", 0);

            (VOID)FatAcquireExclusiveFcb( IrpContext, Fcb );

            FcbAcquired = TRUE;

            FatVerifyFcb( IrpContext, Fcb );

            //
            //  If the file is cached then flush its cache
            //

            Status = FatFlushFile( IrpContext, Fcb, Flush );

            //
            //  Also update and flush the file's dirent in the parent directory if the
            //  file flush worked.
            //

            if (NT_SUCCESS( Status )) {

                //
                //  Insure that we get the filesize to disk correctly.  This is
                //  benign if it was already good.
                //
                //  (why do we need to do this?)
                //

                SetFlag(FileObject->Flags, FO_FILE_SIZE_CHANGED);
#if 0
                FatUpdateDirentFromFcb( IrpContext, FileObject, Fcb, Ccb );
#endif                
                //
                //  Flush the volume file to get any allocation information
                //  updates to disk.
                //

                if (FlagOn(Fcb->FcbState, FCB_STATE_FLUSH_FAT)) {

                    Status = FatFlushFat( IrpContext, Vcb );

                    ClearFlag(Fcb->FcbState, FCB_STATE_FLUSH_FAT);
                }

                //
                //  Set the write through bit so that these modifications
                //  will be completed with the request.
                //

                SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WRITE_THROUGH);
            }

            break;

        case UserDirectoryOpen:

            //
            //  If the user had opened the root directory then we'll
            //  oblige by flushing the volume.
            //

            if (NodeType(Fcb) != FAT_NTC_ROOT_DCB) {

                DebugTrace(0, Dbg, "Flush a directory does nothing\n", 0);
                break;
            }

        case UserVolumeOpen:

            DebugTrace(0, Dbg, "Flush User Volume Open, or root dcb\n", 0);

            //
            //  Acquire exclusive access to the Vcb.
            //

            {
                BOOLEAN Finished;
                Finished = FatAcquireExclusiveSecondaryVcb( IrpContext, Vcb );
                ASSERT( Finished );
            }

            VcbAcquired = TRUE;

            //
            //  Mark the volume clean and then flush the volume file,
            //  and then all directories
            //

            Status = FatFlushVolume( IrpContext, Vcb, Flush );

            //
            //  If the volume was dirty, do the processing that the delayed
            //  callback would have done.
            //

            if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_VOLUME_DIRTY)) {

                //
                //  Cancel any pending clean volumes.
                //

                (VOID)KeCancelTimer( &Vcb->CleanVolumeTimer );
                (VOID)KeRemoveQueueDpc( &Vcb->CleanVolumeDpc );

                //
                //  The volume is now clean, note it.
                //

                if (!FlagOn(Vcb->VcbState, VCB_STATE_FLAG_MOUNTED_DIRTY)) {

                    FatMarkVolume( IrpContext, Vcb, VolumeClean );
                    ClearFlag( Vcb->VcbState, VCB_STATE_FLAG_VOLUME_DIRTY );
                }

                //
                //  Unlock the volume if it is removable.
                //

                if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_REMOVABLE_MEDIA) &&
                    !FlagOn(Vcb->VcbState, VCB_STATE_FLAG_BOOT_OR_PAGING_FILE)) {

                    FatToggleMediaEjectDisable( IrpContext, Vcb, FALSE );
                }
            }

            break;

        default:

            FatBugCheck( TypeOfOpen, 0, 0 );
        }

        FatUnpinBcb( IrpContext, DirentBcb );

        FatUnpinRepinnedBcbs( IrpContext );

    } finally {

        DebugUnwind( FatCommonFlushBuffers );

		if (secondaryRequest)
			DereferenceSecondaryRequest( secondaryRequest );

		if (secondarySessionResourceAcquired) {

			SecondaryReleaseResourceLite( IrpContext, &volDo->Secondary->SessionResource );		
		}

        FatUnpinBcb( IrpContext, DirentBcb );

        if (VcbAcquired) { FatReleaseSecondaryVcb( IrpContext, Vcb ); }

        if (FcbAcquired) { FatReleaseFcb( IrpContext, Fcb ); }

        //
        //  If this is a normal termination then pass the request on
        //  to the target device object.
        //

        if (!AbnormalTermination()) {

            NTSTATUS DriverStatus;
            PIO_STACK_LOCATION NextIrpSp;

            //
            //  Get the next stack location, and copy over the stack location
            //

            NextIrpSp = IoGetNextIrpStackLocation( Irp );

            *NextIrpSp = *IrpSp;

            //
            //  Set up the completion routine
            //

            IoSetCompletionRoutine( Irp,
                                    FatFlushCompletionRoutine,
                                    ULongToPtr( Status ),
                                    TRUE,
                                    TRUE,
                                    TRUE );

            //
            //  Send the request.
            //

            DriverStatus = IoCallDriver(Vcb->TargetDeviceObject, Irp);

            Status = (DriverStatus == STATUS_INVALID_DEVICE_REQUEST) ?
                     Status : DriverStatus;

            //
            //  Free the IrpContext and return to the caller.
            //

            FatCompleteRequest( IrpContext, FatNull, STATUS_SUCCESS );
        }

        DebugTrace(-1, Dbg, "FatCommonFlushBuffers -> %08lx\n", Status);
    }

    return Status;
}
Esempio n. 7
0
NTSTATUS
NtSetTimer (
    IN HANDLE TimerHandle,
    IN PLARGE_INTEGER DueTime,
    IN PTIMER_APC_ROUTINE TimerApcRoutine OPTIONAL,
    IN PVOID TimerContext OPTIONAL,
    IN BOOLEAN WakeTimer,
    IN LONG Period OPTIONAL,
    OUT PBOOLEAN PreviousState OPTIONAL
    )

/*++

Routine Description:

    This function sets an timer object to a Not-Signaled state and sets the timer
    to expire at the specified time.

Arguments:

    TimerHandle - Supplies a handle to an timer object.

    DueTime - Supplies a pointer to absolute of relative time at which the
        timer is to expire.

    TimerApcRoutine - Supplies an optional pointer to a function which is to
        be executed when the timer expires. If this parameter is not specified,
        then the TimerContext parameter is ignored.

    TimerContext - Supplies an optional pointer to an arbitrary data structure
        that will be passed to the function specified by the TimerApcRoutine
        parameter. This parameter is ignored if the TimerApcRoutine parameter
        is not specified.

    WakeTimer - Supplies a boolean value that specifies whether the timer
        wakes computer operation if sleeping

    Period - Supplies an optional repetitive period for the timer.

    PreviousState - Supplies an optional pointer to a variable that will
        receive the previous state of the timer object.

Return Value:

    TBS

--*/

{

    BOOLEAN AssociatedApc;
    BOOLEAN Dereference;
    PETHREAD ExThread;
    PETIMER ExTimer;
    LARGE_INTEGER ExpirationTime;
    KIRQL OldIrql1;
    KPROCESSOR_MODE PreviousMode;
    BOOLEAN State;
    NTSTATUS Status;

    //
    // Establish an exception handler, probe the due time and previous state
    // address if specified, reference the timer object, and set the timer
    // object. If the probe fails, then return the exception code as the
    // service status. Otherwise return the status value returned by the
    // reference object by handle routine.
    //

    try {

        //
        // Get previous processor mode and probe previous state address
        // if necessary.
        //

        PreviousMode = KeGetPreviousMode();
        if (PreviousMode != KernelMode) {
            if (ARGUMENT_PRESENT(PreviousState)) {
                ProbeForWriteBoolean(PreviousState);
            }

            ProbeForRead(DueTime, sizeof(LARGE_INTEGER), sizeof(ULONG));
        }

        //
        // Check argument validity.
        //

        if (Period < 0) {
            return STATUS_INVALID_PARAMETER_6;
        }

        //
        // Capture the expiration time.
        //

        ExpirationTime = *DueTime;

        //
        // Reference timer object by handle.
        //

        Status = ObReferenceObjectByHandle(TimerHandle,
                                           TIMER_MODIFY_STATE,
                                           ExTimerObjectType,
                                           PreviousMode,
                                           (PVOID *)&ExTimer,
                                           NULL);

        //
        // If this WakeTimer flag is set, return the appropiate informational
        // success status code.
        //

        if (NT_SUCCESS(Status) && WakeTimer && !PoWakeTimerSupported()) {
            Status = STATUS_TIMER_RESUME_IGNORED;
        }

        //
        // If the reference was successful, then cancel the timer object, set
        // the timer object, dereference time object, and write the previous
        // state value if specified. If the write of the previous state value
        // fails, then do not report an error. When the caller attempts to
        // access the previous state value, an access violation will occur.
        //

        if (NT_SUCCESS(Status)) {
            ExAcquireSpinLock(&ExTimer->Lock, &OldIrql1);

            if (ExTimer->ApcAssociated) {
                ExThread = CONTAINING_RECORD(ExTimer->TimerApc.Thread, ETHREAD, Tcb);
                ExAcquireSpinLockAtDpcLevel(&ExThread->ActiveTimerListLock);
                RemoveEntryList(&ExTimer->ActiveTimerListEntry);
                ExTimer->ApcAssociated = FALSE;
                ExReleaseSpinLockFromDpcLevel(&ExThread->ActiveTimerListLock);
                KeCancelTimer(&ExTimer->KeTimer);
                KeRemoveQueueDpc(&ExTimer->TimerDpc);
                KeRemoveQueueApc(&ExTimer->TimerApc);
                Dereference = TRUE;

            } else {
                KeCancelTimer(&ExTimer->KeTimer);
                Dereference = FALSE;
            }

            //
            // Read the current state of the timer.
            //

            State = KeReadStateTimer(&ExTimer->KeTimer);

            //
            // If this is a wake timer ensure it's on the wake timer list
            //

            ExTimer->WakeTimer = WakeTimer;
            ExAcquireSpinLockAtDpcLevel(&ExpWakeTimerListLock);
            if (WakeTimer) {
                if (!ExTimer->WakeTimerListEntry.Flink) {
                    InsertTailList(&ExpWakeTimerList, &ExTimer->WakeTimerListEntry);
                }
            } else {
                if (ExTimer->WakeTimerListEntry.Flink) {
                    RemoveEntryList(&ExTimer->WakeTimerListEntry);
                    ExTimer->WakeTimerListEntry.Flink = NULL;
                }
            }
            ExReleaseSpinLockFromDpcLevel(&ExpWakeTimerListLock);

            //
            // If an APC routine is specified, then initialize the APC, acquire the
            // thread's active time list lock, insert the timer in the thread's
            // active timer list, set the timer with an associated DPC, and set the
            // associated APC flag TRUE. Otherwise set the timer without an associated
            // DPC, and set the associated APC flag FALSE.
            //

            ExTimer->Period = Period;
            if (ARGUMENT_PRESENT(TimerApcRoutine)) {
                ExThread = PsGetCurrentThread();
                KeInitializeApc(&ExTimer->TimerApc,
                                &ExThread->Tcb,
                                CurrentApcEnvironment,
                                ExpTimerApcRoutine,
                                (PKRUNDOWN_ROUTINE)NULL,
                                (PKNORMAL_ROUTINE)TimerApcRoutine,
                                PreviousMode,
                                TimerContext);

                ExAcquireSpinLockAtDpcLevel(&ExThread->ActiveTimerListLock);
                InsertTailList(&ExThread->ActiveTimerListHead,
                               &ExTimer->ActiveTimerListEntry);

                ExTimer->ApcAssociated = TRUE;
                ExReleaseSpinLockFromDpcLevel(&ExThread->ActiveTimerListLock);
                KeSetTimerEx(&ExTimer->KeTimer,
                             ExpirationTime,
                             Period,
                             &ExTimer->TimerDpc);

                AssociatedApc = TRUE;

            } else {
                KeSetTimerEx(&ExTimer->KeTimer,
                             ExpirationTime,
                             Period,
                             NULL);

                AssociatedApc = FALSE;
            }

            ExReleaseSpinLock(&ExTimer->Lock, OldIrql1);

            //
            // Dereference the object as appropriate.
            //

            if (Dereference) {
                ObDereferenceObject((PVOID)ExTimer);
            }

            if (AssociatedApc == FALSE) {
                ObDereferenceObject((PVOID)ExTimer);
            }

            if (ARGUMENT_PRESENT(PreviousState)) {
                try {
                    *PreviousState = State;

                } except(ExSystemExceptionFilter()) {
                }
            }
        }

    //
    // If an exception occurs during the probe of the current state address,
    // then always handle the exception and return the exception code as the
    // status value.
    //

    } except(ExSystemExceptionFilter()) {
        return GetExceptionCode();
    }

    //
    // Return service status.
    //

    return Status;
}
Esempio n. 8
0
NTSTATUS
NtCancelTimer (
    IN HANDLE TimerHandle,
    OUT PBOOLEAN CurrentState OPTIONAL
    )

/*++

Routine Description:

    This function cancels a timer object.

Arguments:

    TimerHandle - Supplies a handle to an timer object.

    CurrentState - Supplies an optional pointer to a variable that will
        receive the current state of the timer object.

Return Value:

    TBS

--*/

{

    BOOLEAN Dereference;
    PETHREAD ExThread;
    PETIMER ExTimer;
    KIRQL OldIrql1;
    KPROCESSOR_MODE PreviousMode;
    BOOLEAN State;
    NTSTATUS Status;

    //
    // Establish an exception handler, probe the current state address if
    // specified, reference the timer object, and cancel the timer object.
    // If the probe fails, then return the exception code as the service
    // status. Otherwise return the status value returned by the reference
    // object by handle routine.
    //

    try {

        //
        // Get previous processor mode and probe current state address if
        // necessary.
        //

        PreviousMode = KeGetPreviousMode();
        if ((PreviousMode != KernelMode) && (ARGUMENT_PRESENT(CurrentState))) {
            ProbeForWriteBoolean(CurrentState);
        }

        //
        // Reference timer object by handle.
        //

        Status = ObReferenceObjectByHandle(TimerHandle,
                                           TIMER_MODIFY_STATE,
                                           ExTimerObjectType,
                                           PreviousMode,
                                           (PVOID *)&ExTimer,
                                           NULL);

        //
        // If the reference was successful, then cancel the timer object,
        // dereference the timer object, and write the current state value
        // if specified. If the write attempt fails, then do not report an
        // error. When the caller attempts to access the current state value,
        // an access violation will occur.
        //

        if (NT_SUCCESS(Status)) {
            ExAcquireSpinLock(&ExTimer->Lock, &OldIrql1);
            if (ExTimer->ApcAssociated) {
                ExThread = CONTAINING_RECORD(ExTimer->TimerApc.Thread, ETHREAD, Tcb);
                ExAcquireSpinLockAtDpcLevel(&ExThread->ActiveTimerListLock);
                RemoveEntryList(&ExTimer->ActiveTimerListEntry);
                ExTimer->ApcAssociated = FALSE;
                ExReleaseSpinLockFromDpcLevel(&ExThread->ActiveTimerListLock);
                KeCancelTimer(&ExTimer->KeTimer);
                KeRemoveQueueDpc(&ExTimer->TimerDpc);
                KeRemoveQueueApc(&ExTimer->TimerApc);
                Dereference = TRUE;

            } else {
                KeCancelTimer(&ExTimer->KeTimer);
                Dereference = FALSE;
            }

            if (ExTimer->WakeTimerListEntry.Flink) {
                ExAcquireSpinLockAtDpcLevel(&ExpWakeTimerListLock);

                //
                // Check again as ExGetNextWakeTime might have removed it.
                //
                if (ExTimer->WakeTimerListEntry.Flink) {
                    RemoveEntryList(&ExTimer->WakeTimerListEntry);
                    ExTimer->WakeTimerListEntry.Flink = NULL;
                }
                ExReleaseSpinLockFromDpcLevel(&ExpWakeTimerListLock);
            }

            ExReleaseSpinLock(&ExTimer->Lock, OldIrql1);
            if (Dereference) {
                ObDereferenceObject((PVOID)ExTimer);
            }

            //
            // Read current state of timer, dereference timer object, and set
            // current state.
            //

            State = KeReadStateTimer(&ExTimer->KeTimer);
            ObDereferenceObject(ExTimer);
            if (ARGUMENT_PRESENT(CurrentState)) {
                try {
                    *CurrentState = State;

                } except(ExSystemExceptionFilter()) {
                }
            }
        }

    //
    // If an exception occurs during the probe of the current state address,
    // then always handle the exception and return the exception code as the
    // status value.
    //

    } except(ExSystemExceptionFilter()) {
        return GetExceptionCode();
    }

    //
    // Return service status.
    //

    return Status;
}
Esempio n. 9
0
VOID
ExTimerRundown (
    )

/*++

Routine Description:

    This function is called when a thread is about to be terminated to
    process the active timer list. It is assumed that APC's have been
    disabled for the subject thread, thus this code cannot be interrupted
    to execute an APC for the current thread.

Arguments:

    None.

Return Value:

    None.

--*/

{

    BOOLEAN Dereference;
    PETHREAD ExThread;
    PETIMER ExTimer;
    PLIST_ENTRY NextEntry;
    KIRQL OldIrql1;

    //
    // Process each entry in the active timer list.
    //

    ExThread = PsGetCurrentThread();
    ExAcquireSpinLock(&ExThread->ActiveTimerListLock, &OldIrql1);
    NextEntry = ExThread->ActiveTimerListHead.Flink;
    while (NextEntry != &ExThread->ActiveTimerListHead) {
        ExTimer = CONTAINING_RECORD(NextEntry, ETIMER, ActiveTimerListEntry);

        //
        // Increment the reference count on the object so that it cannot be
        // deleted, and then drop the active timer list lock.
        //
        // N. B. The object reference cannot fail and will acquire no mutexes.
        //

        ObReferenceObject(ExTimer);
        ExReleaseSpinLock(&ExThread->ActiveTimerListLock, OldIrql1);

        //
        // Acquire the timer spin lock and reacquire the active time list spin
        // lock. If the timer is still in the current thread's active timer
        // list, then cancel the timer, remove the timer's DPC from the DPC
        // queue, remove the timer's APC from the APC queue, remove the timer
        // from the thread's active timer list, and set the associate APC
        // flag FALSE.
        //
        // N. B. The spin locks for the timer and the active timer list must be
        //  acquired in the order: 1) timer lock, 2) thread list lock.
        //

        ExAcquireSpinLock(&ExTimer->Lock, &OldIrql1);
        ExAcquireSpinLockAtDpcLevel(&ExThread->ActiveTimerListLock);
        if ((ExTimer->ApcAssociated) && (&ExThread->Tcb == ExTimer->TimerApc.Thread)) {
            RemoveEntryList(&ExTimer->ActiveTimerListEntry);
            ExTimer->ApcAssociated = FALSE;
            KeCancelTimer(&ExTimer->KeTimer);
            KeRemoveQueueDpc(&ExTimer->TimerDpc);
            KeRemoveQueueApc(&ExTimer->TimerApc);
            Dereference = TRUE;

        } else {
            Dereference = FALSE;
        }

        ExReleaseSpinLockFromDpcLevel(&ExThread->ActiveTimerListLock);
        ExReleaseSpinLock(&ExTimer->Lock, OldIrql1);
        if (Dereference) {
            ObDereferenceObject((PVOID)ExTimer);
        }

        ObDereferenceObject((PVOID)ExTimer);

        //
        // Raise IRQL to DISPATCH_LEVEL and reacquire active timer list
        // spin lock.
        //

        ExAcquireSpinLock(&ExThread->ActiveTimerListLock, &OldIrql1);
        NextEntry = ExThread->ActiveTimerListHead.Flink;
    }

    ExReleaseSpinLock(&ExThread->ActiveTimerListLock, OldIrql1);
    return;
}
Esempio n. 10
0
VOID
NTAPI
ExTimerRundown(VOID)
{
    PETHREAD Thread = PsGetCurrentThread();
    KIRQL OldIrql;
    PLIST_ENTRY CurrentEntry;
    PETIMER Timer;
    ULONG DerefsToDo;

    /* Lock the Thread's Active Timer List and loop it */
    KeAcquireSpinLock(&Thread->ActiveTimerListLock, &OldIrql);
    CurrentEntry = Thread->ActiveTimerListHead.Flink;
    while (CurrentEntry != &Thread->ActiveTimerListHead)
    {
        /* Get the timer */
        Timer = CONTAINING_RECORD(CurrentEntry, ETIMER, ActiveTimerListEntry);

        /* Reference it */
        ObReferenceObject(Timer);
        DerefsToDo = 1;

        /* Unlock the list */
        KeReleaseSpinLock(&Thread->ActiveTimerListLock, OldIrql);

        /* Lock the Timer */
        KeAcquireSpinLock(&Timer->Lock, &OldIrql);

        /* Lock the list again */
        KeAcquireSpinLockAtDpcLevel(&Thread->ActiveTimerListLock);

        /* Make sure that the timer is valid */
        if ((Timer->ApcAssociated) && (&Thread->Tcb == Timer->TimerApc.Thread))
        {
            /* Remove it from the list */
            RemoveEntryList(&Timer->ActiveTimerListEntry);
            Timer->ApcAssociated = FALSE;

            /* Cancel the timer and remove its DPC and APC */
            KeCancelTimer(&Timer->KeTimer);
            KeRemoveQueueDpc(&Timer->TimerDpc);
            if (KeRemoveQueueApc(&Timer->TimerApc)) DerefsToDo++;

            /* Add another dereference to do */
            DerefsToDo++;
        }

        /* Unlock the list */
        KeReleaseSpinLockFromDpcLevel(&Thread->ActiveTimerListLock);

        /* Unlock the Timer */
        KeReleaseSpinLock(&Timer->Lock, OldIrql);

        /* Dereference it */
        ObDereferenceObjectEx(Timer, DerefsToDo);

        /* Loop again */
        KeAcquireSpinLock(&Thread->ActiveTimerListLock, &OldIrql);
        CurrentEntry = Thread->ActiveTimerListHead.Flink;
    }

    /* Release lock and return */
    KeReleaseSpinLock(&Thread->ActiveTimerListLock, OldIrql);
}
Esempio n. 11
0
VOID
KiCalibrateTimeAdjustment (
    PADJUST_INTERRUPT_TIME_CONTEXT Adjust
    )

/*++

Routine Description:

    This function calibrates the adjustment of time on all processors.

Arguments:

    Adjust - Supplies the operation context.

Return Value:

    None.

--*/

{

    ULONG cl;
    ULONG divisor;
    BOOLEAN Enable;
    LARGE_INTEGER InterruptTime;
    ULARGE_INTEGER li;
    PERFINFO_PO_CALIBRATED_PERFCOUNTER LogEntry;
    LARGE_INTEGER NewTickCount;
    ULONG NewTickOffset;
    LARGE_INTEGER PerfCount;
    LARGE_INTEGER PerfFreq;
    LARGE_INTEGER SetTime;

    //
    // As each processor arrives, decrement the remaining processor count. If
    // this is the last processor to arrive, then compute the time change, and
    // signal all processor when to apply the performance counter change.
    //

    if (InterlockedDecrement((PLONG)&Adjust->KiNumber)) {
        Enable = KeDisableInterrupts();

        //
        // It is possible to deadlock if one or more of the other processors
        // receives and processes a freeze request while this processor has
        // interrupts disabled. Poll for a freeze request until all processors
        // are known to be in this code.
        //

        do {
            KiPollFreezeExecution();
        } while (Adjust->KiNumber != (ULONG)-1);

        //
        // Wait to perform the time set.
        //

        while (Adjust->Barrier);

    } else {

        //
        // Set timer expiration dpc to scan the timer queues once for any
        // expired timers.
        //

        KeRemoveQueueDpc(&KiTimerExpireDpc);
        KeInsertQueueDpc(&KiTimerExpireDpc,
                         ULongToPtr(KiQueryLowTickCount() - TIMER_TABLE_SIZE),
                         NULL);

        //
        // Disable interrupts and indicate that this processor is now
        // in final portion of this code.
        //

        Enable = KeDisableInterrupts();
        InterlockedDecrement((PLONG) &Adjust->KiNumber);

        //
        // Adjust Interrupt Time.
        //

        InterruptTime.QuadPart = KeQueryInterruptTime() + Adjust->Adjustment;
        SetTime.QuadPart = Adjust->Adjustment;

        //
        // Get the current times
        //

        PerfCount = KeQueryPerformanceCounter(&PerfFreq);

        //
        // Compute performance counter for current time.
        //
        // Multiply SetTime * PerfCount and obtain 96-bit result in cl,
        // li.LowPart, li.HighPart.  Then divide the 96-bit result by
        // 10,000,000 to get new performance counter value.
        //

        li.QuadPart = RtlEnlargedUnsignedMultiply((ULONG)SetTime.LowPart,
                                                  (ULONG)PerfFreq.LowPart).QuadPart;

        cl = li.LowPart;
        li.QuadPart =
            li.HighPart + RtlEnlargedUnsignedMultiply((ULONG)SetTime.LowPart,
                                                      (ULONG)PerfFreq.HighPart).QuadPart;

        li.QuadPart =
            li.QuadPart + RtlEnlargedUnsignedMultiply((ULONG)SetTime.HighPart,
                                                      (ULONG)PerfFreq.LowPart).QuadPart;

        li.HighPart = li.HighPart + SetTime.HighPart * PerfFreq.HighPart;
        divisor = 10000000;
        Adjust->NewCount.HighPart = RtlEnlargedUnsignedDivide(li,
                                                              divisor,
                                                              &li.HighPart);

        li.LowPart = cl;
        Adjust->NewCount.LowPart = RtlEnlargedUnsignedDivide(li,
                                                             divisor,
                                                             NULL);

        Adjust->NewCount.QuadPart += PerfCount.QuadPart;

        //
        // Compute tick count and tick offset for current interrupt time.
        //

        NewTickCount = RtlExtendedLargeIntegerDivide(InterruptTime,
                                                     KeMaximumIncrement,
                                                     &NewTickOffset);

        //
        // Apply changes to interrupt time, tick count, tick offset, and the
        // performance counter.
        //

        KiTickOffset = KeMaximumIncrement - NewTickOffset;
        KeInterruptTimeBias += Adjust->Adjustment;
        SharedUserData->TickCount.High2Time = NewTickCount.HighPart;

#if defined(_WIN64)

        SharedUserData->TickCountQuad = NewTickCount.QuadPart;

#else

        SharedUserData->TickCount.LowPart   = NewTickCount.LowPart;
        SharedUserData->TickCount.High1Time = NewTickCount.HighPart;

#endif

        //
        // N.B. There is no global tick count variable on AMD64.
        //

#if defined(_X86_)

        KeTickCount.High2Time = NewTickCount.HighPart;
        KeTickCount.LowPart   = NewTickCount.LowPart;
        KeTickCount.High1Time = NewTickCount.HighPart;

#endif

#if defined(_AMD64_)

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

#else

        SharedUserData->InterruptTime.High2Time = InterruptTime.HighPart;
        SharedUserData->InterruptTime.LowPart   = InterruptTime.LowPart;
        SharedUserData->InterruptTime.High1Time = InterruptTime.HighPart;

#endif

        //
        // Apply the performance counter change.
        //

        Adjust->Barrier = 0;
    }

    KeGetCurrentPrcb()->TickOffset = KiTickOffset;

#if defined(_AMD64_)

    KeGetCurrentPrcb()->MasterOffset = KiTickOffset;

#endif

    HalCalibratePerformanceCounter((LONG volatile *)&Adjust->HalNumber,
                                   (ULONGLONG)Adjust->NewCount.QuadPart);

    //
    // Log an event that the performance counter has been calibrated
    // properly and indicate the new performance counter value.
    //

    if (PERFINFO_IS_GROUP_ON(PERF_POWER)) {
        LogEntry.PerformanceCounter = KeQueryPerformanceCounter(NULL);
        PerfInfoLogBytes(PERFINFO_LOG_TYPE_PO_CALIBRATED_PERFCOUNTER,
                         &LogEntry,
                         sizeof(LogEntry));
    }

    KeEnableInterrupts(Enable);
    return;
}
Esempio n. 12
0
VOID
NICStopTheDatapath(
    _In_  PMP_ADAPTER  Adapter)
/*++

Routine Description:

    This function prevents future sends and receives on the data path, then
    prepares the adapter to reach an idle state.

    Although the adapter is entering an idle state, there may still be
    outstanding NBLs that haven't been returned by a protocol.  Call NICIsBusy
    to check if NBLs are still outstanding.

    Runs at IRQL == PASSIVE_LEVEL.

Arguments:

    Adapter                     Pointer to our adapter

Return Value:

    None.

--*/
{
    BOOLEAN fResetCancelled, fSendCancelled;
    PLIST_ENTRY ReceiveListEntry;

    DEBUGP(MP_TRACE, "[%p] ---> NICStopTheDatapath.\n", Adapter);

    PAGED_CODE();

    //
    // Remove this adapter from consideration for future receives.
    //
    MPDetachAdapter(Adapter);

    //
    // Free any queued send operations
    //
    TXFlushSendQueue(Adapter, NDIS_STATUS_FAILURE);

    //
    // Prevent new calls to NICAsyncResetOrPauseDpc
    //
    fResetCancelled = NdisCancelTimerObject(Adapter->AsyncBusyCheckTimer);

    //
    // Prevent new calls to RXReceiveIndicateDpc.
    //

    for(ReceiveListEntry = Adapter->RecvDpcList.Flink;
         ReceiveListEntry != &Adapter->RecvDpcList;
         ReceiveListEntry = ReceiveListEntry->Flink)
    {
        PMP_ADAPTER_RECEIVE_DPC ReceiveDpc = CONTAINING_RECORD(ReceiveListEntry, MP_ADAPTER_RECEIVE_DPC, Entry);
        KeRemoveQueueDpc(&ReceiveDpc->Dpc);
    }

    //
    // Prevent new calls to TXSendCompleteDpc.
    //
    fSendCancelled = NdisCancelTimerObject(Adapter->SendCompleteTimer);

    //
    // Wait for any DPCs (like our reset and recv timers) that were in-progress
    // to run to completion.  This is slightly expensive to call, but we don't
    // mind calling it during MiniportHaltEx, since it's not a performance-
    // sensitive path.
    //
    KeFlushQueuedDpcs();

    if (fSendCancelled)
    {
        // Free resources associated with a pending (but cancelled) send
    }

    if (fResetCancelled)
    {
        // Free resources associated with a pending (but cancelled) reset
    }

    //
    // Double-check that there are still no queued receive operations
    //
    for(ReceiveListEntry = Adapter->RecvDpcList.Flink;
         ReceiveListEntry != &Adapter->RecvDpcList;
         ReceiveListEntry = ReceiveListEntry->Flink)
    {
        RXFlushReceiveQueue(Adapter, CONTAINING_RECORD(ReceiveListEntry, MP_ADAPTER_RECEIVE_DPC, Entry));
    }

    //
    // Double-check that there are still no queued send operations
    //
    TXFlushSendQueue(Adapter, NDIS_STATUS_FAILURE);


    DEBUGP(MP_TRACE, "[%p] <--- NICStopTheDatapath.\n", Adapter);
}