Windows System Software -- Consulting, Training, Development -- Unique Expertise, Guaranteed Results

Home NTDEV

Before Posting...

Please check out the Community Guidelines in the Announcements and Administration Category.

More Info on Driver Writing and Debugging


The free OSR Learning Library has more than 50 articles on a wide variety of topics about writing and debugging device drivers and Minifilters. From introductory level to advanced. All the articles have been recently reviewed and updated, and are written using the clear and definitive style you've come to expect from OSR over the years.


Check out The OSR Learning Library at: https://www.osr.com/osr-learning-library/


Running a timer

IgnoreExceptionIgnoreException Member Posts: 47

I have two different cases that require two different timer layouts which I am trying to configure. First I am trying to figure out how to get a timer to run once at a specified interval and then if a certain case is true I need to be able to cancel that timer and run a new one at a different time interval. The second case is being able to run a timer at the same set interval for a set amount of loops. Both of these timers need to have context to my WDFDEVICE and a custom struct that the timer will use. I also need to be able to cancel a timer when needed (based on input from IOCTL).

Anyways I am fairly sure this is what I am looking for which seems to set the interval for a single timer pass. But before I could use it I had to first initialize the PKTIMER struct and then set the time. As of now its just set at a static 1ms relative time (I will multiply it by a multiplier later to be able to set a time thats a multiple of 1ms). That being said I am confused about the PKDPC / custom DPC part which seems to be the call back function which will actually get called when the time expires. Lastly, just to make sure this is all ran on the same kernel thread?

    PKTIMER timer;
    KeInitializeTimer(&timer);

    if (timer == NULL) {
        DebugMessage("Timer is null! \n");
        return STATUS_CANCELLED;
    }

    LARGE_INTEGER expiration; 
    expiration.QuadPart = -10000; // As of now this time is 10,000nano * 100nano = 1ms  

    KDEFERRED_ROUTINE KdeferredRoutine;
    KdeferredRoutine();

    PRKDPC dpc;
    KeInitializeDpc(&dpc, ); // Initialize this first and replace NULL in KeSetTimer

    if (!KeSetTimer(timer, expiration, NULL)) {
        DebugMessage("Set Timer Failed! \n");
        return STATUS_CANCELLED;
    }

Comments

  • Doron_HolanDoron_Holan Member - All Emails Posts: 10,828
    Why not use a WDFTIMER to keep it simple?
    d
  • Tim_RobertsTim_Roberts Member - All Emails Posts: 14,832
    edited July 2023

    KeSetTimer only does one-shot timers. To get it to recur, you need to call KeSetTimer again in the callback.

    KeSetTimerEx has the ability to set up a repeating periodic timer.

    No one guarantees that the DPCs will be called on a single thread.

    Tim Roberts, [email protected]
    Software Wizard Emeritus

  • IgnoreExceptionIgnoreException Member Posts: 47

    @Doron_Holan said:
    Why not use a WDFTIMER to keep it simple?

    I was not aware of that but thanks for mentioning it how does it differ from Ke timers?

  • IgnoreExceptionIgnoreException Member Posts: 47
    edited July 2023

    @Doron_Holan said:
    Why not use a WDFTIMER to keep it simple?

    Alright I have done the following with WdfTimer but I have a few questions firstly is this all synchronous with the main driver thread? Secondly, is there a way to cancel a timer from running? Thirdly, is there a way I can modify the call back function to pass in a custom struct? If its not possible and if its synchronous I can just make the struct a global variable instead. Lastly, does the timer only run once because if so I assume I will need to schedule another one from inside the cleanup function (which I have not added yet).

        WDF_TIMER_CONFIG  timerConfig;
        WDF_OBJECT_ATTRIBUTES  timerAttributes;
        WDFTIMER  timerHandle;
        NTSTATUS  status;
    
        WDF_TIMER_CONFIG_INIT(&timerConfig, EvtWdfTimer);
    
        timerConfig.AutomaticSerialization = TRUE;
    
        WDF_OBJECT_ATTRIBUTES_INIT(&timerAttributes);
        timerAttributes.ParentObject = hDevice; // <-- WdfDevice
    
        if (!NT_SUCCESS(status = WdfTimerCreate(&timerConfig, &timerAttributes, &timerHandle))) {
            DebugMessage("WdfTimer could not be created \n");
            return STATUS_CANCELLED;
        }
    
        // Time is denoted in 100nano second intervals. Negative value just means its relative to the systems time
        if (!WdfTimerStart(timerHandle, -10000)) { // Time is 10,000nano * 100nano = 1ms
            return STATUS_CANCELLED;
        }
        return STATUS_SUCCESS;
    }
    
    void EvtWdfTimer(WDFTIMER timer)
    {
    
    }
    
  • MBond2MBond2 Member Posts: 706

    The first question about timers should be how frequently you need one to fire (order of magnitude) and how much tolerance for jitter. Remember that unlike analog systems, digital systems do not jitter equally in all directions - they can only skew towards longer times

    instead of changing between two timers, could you have both active all the time and simply decide in the callback which one should do work and which one should exit immediately?

Sign In or Register to comment.

Howdy, Stranger!

It looks like you're new here. Sign in or register to get started.

Upcoming OSR Seminars
OSR has suspended in-person seminars due to the Covid-19 outbreak. But, don't miss your training! Attend via the internet instead!
Kernel Debugging 13-17 May 2024 Live, Online
Developing Minifilters 1-5 Apr 2024 Live, Online
Internals & Software Drivers 11-15 Mar 2024 Live, Online
Writing WDF Drivers 20-24 May 2024 Live, Online